Hacker News new | ask | show | jobs
by teraflop 3376 days ago
Fun fact: in Java versions 5 and 6, it was actually possible to write valid Java source code with overloaded return types!

The trick is that generic types in Java are subject to type erasure at runtime. Due to an oversight, it was possible to declare a class with methods like:

    String foo(List<X> l);
    double foo(List<Y> l);
which would be erased to:

    String foo(List l);
    double foo(List l);
At runtime, even though the type information for your List was no longer available, the compiler would be able to locate the correct method using the method signature stored in the caller's bytecode, giving the appearance of return-type dispatch. Technically this violates the Java language spec, and javac 7 was updated to be stricter and prevent this sort of code: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6182950

I guess it's ultimately not that mysterious, but I first encountered it "in the wild", and ended up scratching my head for a while before I figured out why our code suddenly stopped compiling when we upgraded the JDK.

2 comments

> giving the appearance of return-type dispatch

It don't know that it was an appearance, my understanding is it is return-type dispatch which is supported by the JVM (but not java).

Interesting. Then, why isn't the bytecode always stored with the caller, that way you can have return-type dispatch?
The Java bytecode stores it, however the Java language normally does not expose it. Having the compiler select the correct overload based on return type would most likely add a lot of complexity to the language itself ( have you seen the current overload resolution rules? ) without much benefit.

I think the compiler actually has to work around that when you narrow the return type of an overriden function: A method Object Base::get() overriden with Integer Child::get() will result in an additional compiler generated Object Child::get() in the bytecode.

Yep. They're called "bridge" methods. Though, interestingly, there's only one point that they're mentioned in the language spec, specifically in the case of erasure. Even though they were needed before erasure for exactly this reason.

https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.htm...

The bytecode for method invocation does store the type of the method (which includes the return type), and it is quite valid for a class file to contain multiple methods that are only distinguishable by their return type. You can't normally do this visibly in Java, but I think it's used for bridge methods and a few other things by the compiler.