Java Forum / General / August 2006
Incomparable types
Jono - 02 Aug 2006 16:14 GMT Hi everyone, I have a reasonably strong .NET background and I have a problem understanding the Class class in Java. The Type class in .NET (along with the typeof() operator and System.Object's GetType() method) seems pretty straightforward to me: an instance of the Type class is instantiated for every type loaded into the system (even with generics). But it's not so easy to understand with Java, it seems. If I try to compile the sample code below it fails on line 3 of the main method. If I explicitly cast the left-hand and right-hand sides of the equality expression (as per line 4) to Class, then the compiler is happy. Please could someone let me know what the subtle difference is that I am missing out on? Thanks, Jono
public class NewClass {
public static void main(String[] args) { Integer i = new Integer(123); String s = "456"; //System.out.println(i.getClass() == s.getClass()); // compilation failure System.out.println(((Class)i.getClass()) == ((Class)s.getClass())); } }
Thomas Hawtin - 02 Aug 2006 13:54 GMT > Hi everyone, > I have a reasonably strong .NET background and I have a problem [quoted text clipped - 8 lines] > happy. Please could someone let me know what the subtle difference is > that I am missing out on?
> public class NewClass { > [quoted text clipped - 9 lines] > > } An object of type Class<capture of ? extends Integer> cannot be the same object as an object of type Class<capture of ? extends String> (unless you write unchecked code, and null is an odd case). The is no type T such that Class<T> is compatible with both of those types. No T simultaneously extends both String and Integer.
Similarly the expression "i instanceof String" and "i == s" are nonsense and will not compile.
Tom Hawtin
Jono - 02 Aug 2006 19:24 GMT Tom, Thank you for your explanation, I'm sure it will finally hit home after a couple of re-reads, but from what I understand the inclusion of generics has been bundled with a new Class class that has some kind of [invisible?] object hierarchy of its own. Presumably this hierarchy exists at some stage during compilation, which is how the compiler knows that i's type isn't convertible to s's type. If you reflect over either of the types at runtime they're both the same java.lang.Class, but then that's probably something to do with the dreaded "type erasure". I welcome your comments. Cheers, Jono
> > Hi everyone, > > I have a reasonably strong .NET background and I have a problem [quoted text clipped - 33 lines] > > Tom Hawtin Patricia Shanahan - 02 Aug 2006 23:10 GMT > Tom, > Thank you for your explanation, I'm sure it will finally hit home after [quoted text clipped - 44 lines] >> >> Tom Hawtin I can see the rule that is being applied, and it is stated in the JLS, but the rule itself makes no sense to me.
The language allows many comparisons that can never have a true result. For example, 2==3 is a valid comparison, with the result false.
Trivially true type comparisons, such as ("A" instanceof String) are accepted.
It is only in the context of type comparisons, and only if the result is false, that the compiler rejects the comparison at compile time.
WHY?
Patricia
Oliver Wong - 02 Aug 2006 23:14 GMT >>> An object of type Class<capture of ? extends Integer> cannot be the same >>> object as an object of type Class<capture of ? extends String> (unless [quoted text clipped - 18 lines] > > WHY? It really should be a warning instead of an error: "Warning: this will always yield true/false, so this is probably not you meant, but the code is still runnable."
I feel the same way about unreachable code. Sometimes I want to intentionally make code unreachable for debugging purposes, so I wish unreachable code was a warning rather than an error. With the Eclipse compiler, you can actually toggle things like these.
- Oliver
Chris Uppal - 03 Aug 2006 09:01 GMT > I can see the rule that is being applied, and it is stated in the JLS, > but the rule itself makes no sense to me. It makes exactly zero sense to me, too.
If you can convert illegal (illegal!) code into legal code by throwing away information in the type declarations, then something is badly wrong.
And I most certainly don't agree with Thomas that
> "i instanceof String" and "i == s" are nonsense Both make perfect sense. If they were nonsense then changing the declared type of "i" and "s" to Object could not possibly make the code coherent -- yet it does...
Just another cretinous design decision from The Powers That Be (but one made some time ago, it hasn't been introduced with generics -- which makes a change).
-- chris
Jono - 03 Aug 2006 10:11 GMT Initially after reading Tom's post I disagreed with his idea that a) 'i == s' and b) 'i instanceof String' were nonsense, but now that it's had a little while to sink in I am on his side. From a theoretical perspective, the expressions are nonsense. If you tried to perform the same operations in C# (a) using an Int32 and a String, and b) using the 'is' operator), you'd get more informative error messages such as:
a) "Operator '==' cannot be applied to operands of type 'int' and 'string'", and b) "The given expression is never of the provided ('string') type".
This all boils down to the compiler performing type safety checks and realising that Integer and String aren't in the same branch of the type hierarchy.
Also, I now realise that the Tiger version of Java's class java.lang.Class is a generic class whose type parameter denotes the type that the Class object represents. Because the hierarchy of generic types is a little complicated (the fictional GenericType<B> does not derive from GenericType<A>, even though type B extends type A) there is now no way to compare instances of Class objects because they refer to different types. Actually, the last statement is a bit of a lie. I've seen the <?> and <capture of ? extends type> syntax but I haven't understood it fully yet.
As an aside, I'm enjoying the concept of online compilers such as this one for C# 2.0: http://www.caller.me.uk/Compilr/C-Sharp.aspx
Cheers,
Jono
> > I can see the rule that is being applied, and it is stated in the JLS, > > but the rule itself makes no sense to me. [quoted text clipped - 17 lines] > > -- chris Mike Schilling - 04 Aug 2006 08:59 GMT > I can see the rule that is being applied, and it is stated in the JLS, > but the rule itself makes no sense to me. > > The language allows many comparisons that can never have a true result. > For example, 2==3 is a valid comparison, with the result false. Likewise:
byte b; ... if (b > 500)
and
Object o; ... if (o == new Object())
Both are legal yet can never be true.
> Trivially true type comparisons, such as ("A" instanceof String) are > accepted. > > It is only in the context of type comparisons, and only if the result is > false, that the compiler rejects the comparison at compile time. It seems as if this is an attempt to make Java seem more strongly typed than it actually is, so that e.g.
int i; Integer j; String s; ... if (s == j)
is deemed not false but undefined, the way that
if (s == i)
is, in fact, not false but undefined, since equality of references and scalars is not defined.
This is nonsense, of course. Determining whether two references are equal is perfectly well defined, as shown by the legality of:
if ((Object)s == (Object)i)
where the casts do not change the value of the references, but simply remove the compiler's unwillingness to generate the proper code.
Eric Sosman - 02 Aug 2006 16:20 GMT Jono wrote On 08/02/06 11:14,:
> Hi everyone, > I have a reasonably strong .NET background and I have a problem [quoted text clipped - 24 lines] > > } I see nothing wrong with your code -- and neither does javac. When I remove the //, your code compiles just fine for me and outputs "false" twice.
 Signature Eric.Sosman@sun.com
Jono - 02 Aug 2006 16:59 GMT My compiler version is 1.5.0_07, but I also tried with 1.5.0_06 and got the same result. The class won't compile if I uncomment the 3rd line of main().
NewClass.java:23: incomparable types: java.lang.Class<c apture of ? extends java.lang.Integer> and java.lang.Class<capture of ? extends java.lang.String> System.out.println(i.getClass() == s.getClass()); ^ 1 error
> Jono wrote On 08/02/06 11:14,: > > Hi everyone, [quoted text clipped - 29 lines] > javac. When I remove the //, your code compiles just fine > for me and outputs "false" twice. Jono - 02 Aug 2006 17:16 GMT Not having a 1.4.2 compiler at my disposal, I used the online Java compiler at http://www.innovation.ch/ and the class compiled without errors. Also, the 1.5.* compiler's error message has something to do with angle-brackets so I presume that what used to hold true for Java has been broken by the addition of generics to the language. I'd still like someone to shed some light on the change, if possible. Regards, Jono
> My compiler version is 1.5.0_07, but I also tried with 1.5.0_06 and got > the same result. The class won't compile if I uncomment the 3rd line of [quoted text clipped - 41 lines] > > javac. When I remove the //, your code compiles just fine > > for me and outputs "false" twice. Oliver Wong - 02 Aug 2006 17:25 GMT > My compiler version is 1.5.0_07, but I also tried with 1.5.0_06 and got > the same result. The class won't compile if I uncomment the 3rd line of [quoted text clipped - 7 lines] > ^ > 1 error See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6448774
- Oliver
Jono - 02 Aug 2006 19:03 GMT Hi Oliver, I believe that the bug you pointed out is specific to one of the beta versions of Java 6, and the referenced page doesn't give any more clues as to what's happening when the sample code gets compiled by a Java 5 compiler. I've been reading reams of documents with phrases like type erasure, reification and synthetic bridge methods and I really hope the only answer doesn't lie buried inside one of them! Cheers, Jono
> > My compiler version is 1.5.0_07, but I also tried with 1.5.0_06 and got > > the same result. The class won't compile if I uncomment the 3rd line of [quoted text clipped - 11 lines] > > - Oliver Oliver Wong - 02 Aug 2006 19:34 GMT > Hi Oliver, > I believe that the bug you pointed out is specific to one of the beta [quoted text clipped - 5 lines] > Cheers, > Jono Sorry, I didn't realize that Java didn't allow you to compare for equality two types which "could not possibly be equal", so actually this bug that I linked to was probably a red herring.
- Oliver
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|