1
var test = "Hello World!";

In Java 10+, the above snippet compiles, and test is inferred to be a String at compile-time.

However, we can use the conditional (ternary) operator to return different types, such as:

var test = new Random().nextBoolean() ? "Hello World!" : 123;

If we were to print test.getClass() at runtime, it would output either:

  • class java.lang.String
  • class java.lang.Integer

This makes sense, but what would the type of test be at compile-time? Would it be Object, or something else?

Naman
  • 27,789
  • 26
  • 218
  • 353
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • 1
    Possibly duplicate/related to https://stackoverflow.com/questions/49558895/why-am-i-getting-an-assertionerror-when-assigning-arrays-aslist-to-var-directl – Naman May 01 '19 at 15:08
  • @Naman I'd argue against it being a duplicate, mainly because my code compiles on Java 12, and even running their code (that they say doesn't compile) on Java 12 compiles just fine for me. My question was more about, what is the compile-time type of this variable and why? I can see how the two are related, though. – Jacob G. May 01 '19 at 15:11
  • 1
    Well, one can certainly do so and that's one of the reasons why I didn't actually vote to close this. But currently, the question and its answer are neither complementing nor very clear. That said, I am still leaving this to the community further to vote accordingly. Related to the link, the answer reads that the bug was fixed in a later version of JDK10. – Naman May 01 '19 at 15:14
  • [related](https://stackoverflow.com/questions/50022830/advantages-drawbacks-of-var-in-java-10/50022921#50022921) look at the last sample for example – Eugene May 03 '19 at 13:33

1 Answers1

3

Interestingly, Intellij tells me that the type of test is not Object, but rather this beast:

java.io.Serializable & Comparable<? extends java.io.Serializable & Comparable<?> & constant.Constable & constant.ConstantDesc> & constant.Constable & constant.ConstantDesc

The reason why this is the case is because the compiler infers the type of the variable to be the closest common superclasses between String and Integer, which are in-fact Serializable, Comparable, Constable, and ConstantDesc in Java 12.

There's an interesting article that elaborates on impossible types, which are what these types are known as (since they can only be inferred by the compiler): Representing the Impractical and Impossible with JDK 10 “var”

If we were to return objects that are entirely unrelated, such as Integer and ByteArrayOutputStream, then we would see that Java would infer the compile-time type of test to be Object:

var test = new Random().nextBoolean() ? 123 : new ByteArrayOutputStream();
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • 1
    [This Q&A](https://stackoverflow.com/q/43987285/2711488) also discusses the possibility of having variables with a non-denotable type, also with pre-Java 10 constructs. – Holger May 03 '19 at 11:48
  • This is covered by the third bullet of [JLS 15.25.3](https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.25.3). What you called the “closest common superclass” is referred to here as the *lub* or *least upper bound* of the two types. But you have the intuition correct. – Stuart Marks Jun 11 '19 at 14:59