[456] in java-interest

home help back first fref pref prev next nref lref last post

Re: Array Subclassing and IncompatibleTypeException

daemon@ATHENA.MIT.EDU (Arthur van Hoff)
Fri Jun 23 01:47:32 1995

From: Arthur.Vanhoff@Eng.Sun.COM (Arthur van Hoff)
To: majordom@java.Eng.Sun.COM (William Cook)
Date: Thu, 22 Jun 1995 22:21:48 -0800 (PDT)
Cc: java-interest@java.Eng.Sun.COM
In-Reply-To: <ac0f530004021004a2f0@[199.242.245.12]> from "William Cook" at Jun 22, 95 06:08:39 pm


Hi William,

Thanks for your mail. You have touched upon a very interesting topic.
When assigning an element to an array of objects we always test the
type of the new element against the actual type of the array, not the
declared type. This may sometimes lead to unexpected results, but it
fills a big hole in the type system.

Recently Bill Joy, Guy Steel, David Ungar and Ole Madsen have been 
evaluating the Java language and they have pointed out that our current
array type system may not be the optimal choice. As it turns we only
allow co-variant argument types on array types and not on class types.
We are working on a proposal which, in the future, allows us to express 
arrays as parameterized types without the requirement for co-variant arguments.
I'll let you know the result of this discussion.

By the way, the type check on assignment can be eliminated in a lot of
cases using a simple static type analysis of the byte codes. However, we 
currently don't implement this.

> I was looking at the Java language specification, and am very impressed with
> its simplicity and cleanness. But I was surprised to learn that
> 
> "If class A is a superclass of class B (i.e., B extends A) then
> A[] is a superclass of B[]" (from the Array Detail section)
> 
> Including something like this has a tendency to make a type system unsound.
> 
> --------background--------------
> If we make the array methods visible, we get something like
>     interface A[]  { 
>                 A get(long index);
>                 void set(long index, A value);
>                 long length();
>         }
>     interface B[] extends A[]   { 
>                 B get(long index);
>                 void set(long index, B value);
>                 long length();
>         }
> Note that the get and set methods are redefined with a different result/parameter type.
> In general, subclassing allows you to use a B[] where an A[] is expected.
> 
> The redefinition of get works find because we are only taking values out of the array 
> (you will always get B's, which are compatible with A's). 
> 
> But if you try to put things into the array, you run into problems. You can try to
> add an A value to the array, but this is illegal.
> 
> For more info, see
> W. Cook. ÒA proposal for making Eiffel type-safe.Ó Proc. European Conf. on Object-Oriented Programming, British Computing Society Workshop Series, 1989,  pp. 57Ð70. Also  The Computer Journal  32(4):305Ð311, 1989.
> -------end of digression---------------
> 
> To make this more concrete, consider this program.
>                 B arrayB[] = new B[2];  // normal initialization
>                 A arrayA[] = arrayB;    // this is legal because B[] is a subclass of A[]
>                 arrayA[0] = new A();    // this looks legal on the face of it
> However, the last assignment is not valid because arrayA is really a value of class B[],
> which cannot contain values of class A.
> 
> I ran this program in Java (alpha2 NT) and got an "IncompatibleTypeException" on
> line 3. (This was better than what I got when I tried a similar trick on Eiffel, which 
> crashed very badly...the problems in Eiffel were worse because they allow
> any method to be incorrectly overridden with different types.)
> 
> Java seems to be interpreting this case as very similar to narrowing, which uses
> a runtime check. But it seems to me that IncompatibleTypeException is a little bit
> odd. It seems to be a special case for arrays.
> 
> I was curious: does Java perform a type check on every array store?
> 
> I looked in the virtual machine spec: 
> 
> -----------------------
> Bytecode: aastore
> 
> Store into object reference array
>         ..., array, index, value => ...
> array should be an array of handles to objects or to arrays, index should be an integer, and
> value a handle to an object or array. The handle value is stored at position index in array. 
> 
> If array is null, a NullPointerException is thrown. If index is not within the bounds of
> array, an ArrayIndexOutOfBoundsException is thrown.
> 
> The actual type of value should be conformable with the actual type of the elements of the
> array. For example, it is legal to store and instance of class Thread in an array of class
> Object, but not vice versa. An IncompatibleTypeException is thrown if an attempt is made
> to store an incompatible object reference.
> -----------------------
> 
> Does it check that "type of value should be conformable with the actual type" on every
> assignment?
> 
> -William Cook, Ph.D., william@bamsoft.com
> BAM! Software, Inc.
> 
> PS: note that IncompatibleTypeException also seems to be used if you try to call newInstance() on an interface. This appears to be possible because intefaces are actually instances of class "Class". It might be better to have two exceptions for these diff> erent errors.


Have fun,

	Arthur van Hoff (avh@eng.sun.com)
	http://java.sun.com/people/avh/
	Sun Microsystems Inc, M/S UPAL02-301,
	100 Hamilton Avenue, Palo Alto CA 94301, USA
	Tel: +1 415 473 7242, Fax: +1 415 473 7104
-
Note to Sun employees: this is an EXTERNAL mailing list!
Info: send 'help' to java-interest-request@java.sun.com

home help back first fref pref prev next nref lref last post