[453] in java-interest
Array Subclassing and IncompatibleTypeException
daemon@ATHENA.MIT.EDU (William Cook)
Thu Jun 22 21:46:32 1995
Date: Thu, 22 Jun 95 18:08:39 PDT
To: java-interest@java.sun.com
From: william@bamsoft.com (William Cook)
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 different errors.
-
Note to Sun employees: this is an EXTERNAL mailing list!
Info: send 'help' to java-interest-request@java.sun.com