JDK8 type inference issue
Asked Answered
A

1

6

I'm trying to run the following code which is compiled fine under JDK8 thanks to type inference:

public static <A,B> B convert(A a) {
  return (B) new CB();
}
public static void main(String[] args) {
  CA a = new CA();
  CB b = convert(a); //this runs fine
  List<CB> bl = Arrays.asList(b); //this also runs fine
  List<CB> bl1 = Arrays.asList(convert(a)); //ClassCastException here
}

However, running this throws ClassCastException: CB cannot be cast to [Ljava.lang.Object, but the CB b = convert(a) works fine.

Any idea why?

Ahimsa answered 18/8, 2016 at 15:20 Comment(10)
Wait, what is convert even doing? It's argument is ignored, so it doesn't matter what's being passed in.Topheavy
Which JRE version do you use? I get a java.lang.VerifyError: Bad type on operand stack with 1.8.0_92. Btw, using a type witness works for me: List<CB> bl1 = Arrays.asList(Test.<CA, CB>convert(a));Darnley
@StefanZobel indeed that works but I've around 150 usages and changing that manually is not easy - I was hoping JDK8 would do inference automagicallyAhimsa
@StefanZobel using JDK 1.8.0_31Ahimsa
Ignore my java.lang.VerifyError result. Forgot to mention that I've used the Eclipse builtin compiler.Darnley
With javac from 1.8.0_92 and 1.8.0_102 I also get the CCE.Darnley
javac from jdk9_ea_b122 casts to CB[] instead of Object[]. Not much better.Darnley
That’s a perfectly valid outcome. You created a generic method that allows to infer arbitrary return types, so the compiler may infer CB[] rather than inferring CB and do varargs processing.Convulsive
@StefanZobel you're using an Eclipse compiler from 2014, the wrong code generation leading to VerifyError has been fixed in version 4.5.Sinter
@StephanHerrmann Yeah, I know. I took the first Java 8 capable Eclipse installation I could find on the computer (not my regular workstation) that I was using at that moment - and that was an old Eclipse Luna (I guess). Shortly after I posted the VerifyError result it made "click" and I knew that I had f**cked up. I'm not using this for serious Java 8 work.Darnley
C
6

Whenever you create a generic method with a signature that promises to return whatever the caller wishes, you are asking for trouble. You should have got an “unchecked” warning from the compiler which basically means: unexpected ClassCastExceptions may occur.

You expect the compiler to infer

List<CB> bl1 = Arrays.asList(YourClass.<CA,CB>convert(a));

whereas the compiler actually inferred

List<CB> bl1 = Arrays.asList(YourClass.<CA,CB[]>convert(a));

as far as I know, because it prefers method invocations not requiring a varargs packaging (which is compatible with pre-varargs code).

This fails because your convert method does not return the expected array type.

Convulsive answered 18/8, 2016 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.