• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Overloading compareTo(), compiler error?

 
Ranch Hand
Posts: 179
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi guys.

Found a somewhat sneaky compiler error I was curious if someone could explain a little. Consider this code:



Obviously I would never implement anything like this, but I got a little "stumped" to find that the compiler didn't allow it. In my eyes it's a perfectly legal override, and works fine if we don't implement Comparable. Yet when we do add the 'implements' keyword for the class, it is not allowed. The error was this:


javac TestC1.java
TestC1.java:4: name clash: compareTo(java.lang.Object) in TestC1 and compareTo(T) in java.lang.Comparable<TestC1> have the same erasure, yet neither overrides the other
public class TestC1 implements Comparable<TestC1>, Comparator {
^
1 error



I'm guessing that this error has to do with the generics type-erasure. If I'm not mistaking, after compilation this class will implement "just Comparator", but the compiler would have checked that the only compareTo()-calls for this class is of type compareTo(TestC1),
seeing as that's the generic type of Comparable<> that the class implements. So why the error?

// Andreas
 
Ranch Hand
Posts: 808
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I can't help explain what's going on, but also note that the code compiles if you implement Comparable non-generically.
 
Ranch Hand
Posts: 125
Postgres Database BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
truly weird
 
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's because of type erasure. The compiler throws away generic type arguments. After compilaton, compareTo(TestC1) would look the same as compareTo(Object), because TestC1 is a generic type argument. Since you already have a compareTo(Object) defined, the compiler throws that error because you're not allowed to overload a method if the signatures are the same.
 
Andreas Svenkson
Ranch Hand
Posts: 179
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:It's because of type erasure. The compiler throws away generic type arguments. After compilaton, compareTo(TestC1) would look the same as compareTo(Object), because TestC1 is a generic type argument. Since you already have a compareTo(Object) defined, the compiler throws that error because you're not allowed to overload a method if the signatures are the same.



Ah, so just so I get you right... you're saying that the type erasure actually changes the method signature of



to



Is that right? Funny, I wouldn't have expected that since the specific method isn't using generics directly, but I suppose it makes sense...

// Andreas
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As far as the compiler is concerned, your compareTo(TestC1) method is actually a <T> compareTo(T) method. T is replaced by Object after the compiler checks that you are really using TestC1 everywhere, instead of just any other type.
 
Andreas Svenkson
Ranch Hand
Posts: 179
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:As far as the compiler is concerned, your compareTo(TestC1) method is actually a <T> compareTo(T) method. T is replaced by Object after the compiler checks that you are really using TestC1 everywhere, instead of just any other type.



Hmm, yes... I understand you, I just gotta burn the functionality into my brain correctly...

So to be clear, there are 2 steps taking place here...

1: the generic type <T> is replaced by the specified type TestC1 during compilation, and the compiler enforces type-safety for any such methods
2: then there is the type-erasure, after the compile-time type safety has been enforced, which actually replaces the specific type TestC1 with type Object

Man I somehow feel like this is both news to me, and at the same not

I knew this before, but it feels more strange in this scenario because we have explicitly implemented a method compareTo(TestC1) with a specific type. But the method is, as you say, overriding a <T> compareTo(T) generic method, so ofcourse type erasure should convert it to a compareTo(Object) signature...

// Andreas
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You got it
 
Andreas Svenkson
Ranch Hand
Posts: 179
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, here's something weird... I recently got a hand of a Java decompiler, and having first compiled the following code:



... after opening the class file in the decompiler, it showed the following:



I'm almost suspecting the decompiler is flawed, I'm using the one from: http://java.decompiler.free.fr
What do you make of this Stephan? I mean according to this, the type erasure doesn't change the signature of compareTo(TestGenInt) to compareTo(Object).

But perhaps I'm misinterpreting the java decompiler.... maybe it's not the actual bytecode that its attempting to show me, but rather how the program was written........

EDIT: Another thing... it seems pretty damn weird to me that the decompiler is able to reconstruct the generic types - those only exist during compilation. so shouldn't be available at all in the class file?

// Andreas
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I'm not really familiar with the inner workings of the java compiler, but I imagine that the generic information is only removed by the JIT compiler, right before execution of the program.

This makes sense, because even in the absence of the original source code, the java compiler still needs to check whether newly written code interacting with an existing (generic) class performs type safe operations.

So while the generic types still exist in the byte code, they will be removed by the JIT compiler.
 
Andreas Svenkson
Ranch Hand
Posts: 179
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hm, yeah that's a good point...

Never really considered there was JIT compiler aswell as the "ordinary" compiler, are you saying this JIT compiler is a part of the JVM,invoked by 'java', and that it "compiles the byte code" before it runs it? Details :P But I can't help but be curious...

Still, if the type-erasure doesn't take place until runtime (or just before it), it seems a bit odd that the javac compiler notices any problems with the methods having the same signature (in the above case I mean, due to the type-erasure), if the type-erasure doesn't happen until we invoke 'java'...

What about seeing that the JVM actually runs, is there a better way to see that code than to use a decompiler?

// Andreas
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, the JVM compiles bytecode to native code before it executes the code.

Well, verifying whether your code is legal comes before actually compiling it. Ideally, you want to do all the checking before a single piece of byte code is written, so the JVM can assume that .class files are always correct. Wouldn't it be annoying that you only found out your program was wrong when you started the JVM, instead of when you call javac?

The fact that javac doesn't immediately remove generic types, doesn't mean that it can't determine how the method signatures will end up looking when erasure does take place.

I'm not exactly sure what you mean by your last question. Do you mean you want to see the actual code that the JVM runs? At this point, it looks nothing like Java anymore, and a Java program can't easily be reconstructed from it.
 
Andreas Svenkson
Ranch Hand
Posts: 179
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:Yes, the JVM compiles bytecode to native code before it executes the code.



Obviously, stupid me, how else would the plattform-independancy be possible

Stephan van Hulst wrote:Well, verifying whether your code is legal comes before actually compiling it. Ideally, you want to do all the checking before a single piece of byte code is written, so the JVM can assume that .class files are always correct. Wouldn't it be annoying that you only found out your program was wrong when you started the JVM, instead of when you call javac?

The fact that javac doesn't immediately remove generic types, doesn't mean that it can't determine how the method signatures will end up looking when erasure does take place.



True true, even if it doesn't actually perform the type erasure it can still predict what they will be.

Stephan van Hulst wrote:I'm not exactly sure what you mean by your last question. Do you mean you want to see the actual code that the JVM runs? At this point, it looks nothing like Java anymore, and a Java program can't easily be reconstructed from it.



Right... what I was after was seeing what the code looks like after the type-erasure, but I guess that might not be possible. It's funny, I never really considered how the JVM actually handles the byte code, I just thought of it as a program that "knew how to run java programs compiled to byte code" and that was that. But the way you describe it makes sense ofcourse. It just annoys me, I guess I would practically have to be able to read machine-level binary code to really know what the cpu sees when it executes the program.

Stupid computers

// Andreas
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Andreas Svenkson wrote:Obviously, stupid me, how else would the plattform-independancy be possible

[...]

Right... what I was after was seeing what the code looks like after the type-erasure, but I guess that might not be possible. It's funny, I never really considered how the JVM actually handles the byte code, I just thought of it as a program that "knew how to run java programs compiled to byte code" and that was that.



Actually, some languages are usually interpreted, instead of compiled. In this case, the executable works the same way we would read a program. It reads a line, tells the CPU what to do, and then moves on to the next line.
More information: http://en.wikipedia.org/wiki/Interpreted_language

It just annoys me, I guess I would practically have to be able to read machine-level binary code to really know what the cpu sees when it executes the program.



At this point, it becomes a lot easier to read the Java Language Specification instead. It should give you a good idea of what really goes on behind the scenes.
 
It's just like a fortune cookie, but instead of a cookie, it's pie. And we'll call it ... tiny ad:
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic