How does Java infer the type when using `var` and generic methods without parameters?
Asked Answered
A

2

5

Considering a following example of a generic method without any parameters:

private <T> Set<T> create() {
    return new HashSet<T>();
}

According to the docs, the type will be inferred depending on how the return value is used, i.e., during assignments, from the LHS type defined, for example:

Set<Integer> numbers = create();

How does this play out when using the var keyword?

The following will compile:

var numbers = create();
Aeroplane answered 18/4, 2023 at 9:0 Comment(2)
Is get() supposed to be the same as create() in this example?Myoglobin
yeah, should be create, I mistyped that.. thanks @MyoglobinAeroplane
M
4

For how var works, refer to section 14.4.1 of the JLS.

If the LocalVariableType is var, then let T be the type of the initializer expression when treated as if it did not appear in an assignment context, and were thus a standalone expression (§15.2). The type of the local variable is the upward projection of T with respect to all synthetic type variables mentioned by T (§4.10.5).

To know how the type parameter gets inferred, refer to section 15.12.2.6, where it specifies how the invocation type is determined

If the chosen method is generic and the method invocation does not provide explicit type arguments, the invocation type is inferred as specified in §18.5.2.

Digging deeper into 18.5.2, we find a lot of rules that are not relevant to your situation - about the case of poly expressions (which the method call in the initialiser of var can never be). In the case of not using var, more bounds would be added in this step. It also mentioned what additional bounds to add when there are argument expressions (which your method has none). The relevant part is that T is eventually resolved (section 18.4).

What constraints are on T? Well, you did not write T extends Something, so the only bound is T <: Object. (See the end of section 18.1.3) This just means T must be a subtype of Object. In other words, Object is the only lower bound of T. If you declare the method with <T extend SomeOtherType>, then it would have SomeOtherType as a lower bound.

The section about resolution is quite long, but the relevant thing here is that lower bounds are resolved to their least upper bound, a super type that is more specific than any other common super type the types have.

Since we only have one lower bound, Object, its least upper bound is trivially itself. Therefore, T is inferred to be Object. You can see this by adding the --debug=verboseResolution=all option when compiling:

JavaClass.java:8: Note: resolving method create in type JavaClass to candidate 0
        var s = create();
                ^
  phase: BASIC
  with actuals: no arguments
  with type-args: no arguments
  candidates:
      #0 applicable method found: <T>create()
        (partially instantiated to: ()Set<Object>)
  where T is a type-variable:
    T extends Object declared in method <T>create()
JavaClass.java:8: Note: Deferred instantiation of method <T>create()
        var s = create();
                      ^
  instantiated signature: ()Set<Object>
  target-type: <none>
  where T is a type-variable:
    T extends Object declared in method <T>create()
Mascot answered 18/4, 2023 at 9:53 Comment(0)
A
3

The FAQ about Local Variable Type Inference describes whats happening:

Q8. Can you use var with a diamond on the right-hand side?

Yes, it works, but it’s probably not what you want. Consider:

var list = new ArrayList<>();

This will infer the type of list to be ArrayList<Object>. In general, it’s preferable use an explicit type on the left with diamond on the right, or use var on the left with an explicit type on the right. See the LVTI Style Guidelines, guideline G6, for further information.

That guideline G6 additionally states:

For its inference, diamond can use the target type (typically, the left-hand side of a declaration) or the types of constructor arguments. If neither is present, it falls back to the broadest applicable type, which is often Object. This is usually not what was intended.

Adjectival answered 18/4, 2023 at 9:52 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.