35

After reading and talking about Java 10s new reserved type name var (JEP 286: Local-Variable Type Inference), one question arose in the discussion.

When using it with literals like:

var number = 42;

is number now an int or an Integer? If you just use it with comparison operators or as a parameter it usually doesn't matter thanks to autoboxing and -unboxing. But due to Integers member functions it could matter.

So which type is created by var, a primitive int or class Integer?

Naman
  • 23,555
  • 22
  • 173
  • 290
sweisgerber.dev
  • 1,517
  • 15
  • 34
  • 3
    Nevertheless, one way was to surely try it out, where you could have tried to see that `number instanceof Integer` wouldn't work for your case(as `instanceof` wouldn't work for primitive types). While if the number, on the other hand, would have been casted to `(Integer) 42`. [It would have worked.](https://tio.run/##ZU29DsIgGJzLU9xIBxudGx/AwamjcfikSKiUNvCV1Jg@OzLoordccr8DJdoN/SPnebk5q6AcxYgzWY@XqD5iZOJCabI9xmLJjoP15nIFBRPrksQPEgWsOEKePGujQ43Dvv1Ldc/IemymhZu5DLLzcoX15c4rPd3xLbei2sSW8xs) – Naman Mar 22 '18 at 11:55

4 Answers4

34

var asks the compiler to infer the type of the variable from the type of the initializer, and the natural type of 42 is int. So number will be an int. That is what the JLS example says:

var a = 1;  // a has type 'int' 

And I would be surprised if it worked any other way, when I write something like this, I definitely expect a primitive.

If you need a var as boxed primitive, you could do:

var x = (Integer) 10;  // x is now an Integer
Moti Korets
  • 3,458
  • 2
  • 23
  • 33
Eugene
  • 102,901
  • 10
  • 149
  • 252
  • Thanks for your answer, so goes my thinking, too but do you have a reference for it? – sweisgerber.dev Mar 22 '18 at 09:09
  • 1
    The only "benefit" of having a generic `var` type IMO is the ability to assign dynamic properties to it, C# and JS-like. Like `var a = {}; a.arbitraryProperty = "hey!";` - however, it doesn't seem to be possible (I might be wrong though). – BackSlash Mar 22 '18 at 09:18
  • 2
    @BackSlash you can sort of do it `var x = new Object() { int y; int z; }; int test = x.y;` And that is possible only with types that are inferred by the compiler, see also this https://stackoverflow.com/questions/49410939/useful-applications-of-intersection-types-using-local-type-inference – Eugene Mar 22 '18 at 09:23
  • 1
    @BackSlash I just [read about this](https://developer.oracle.com/java/jdk-10-local-variable-type-inference), it is mostly to reduce the verbosity. I begin to understand where this could be useful, this was restricted to local variable so it would not be a mess like JS (and other language too I think). – AxelH Mar 22 '18 at 11:38
  • 14
    @BackSlash: What you are talking about is *dynamic typing*. What this question is about, is *implicit typing*. Those are two completely different things. – Jörg W Mittag Mar 22 '18 at 12:48
  • 2
    @Eugene You are using the term "syntactic sugar" incorrectly. This is not a purely syntactic transform. – Brian Goetz Mar 22 '18 at 13:27
  • @BrianGoetz thank you for the edit, and yes, it makes a lot of sense that it is more than synthetic sugar... – Eugene Mar 22 '18 at 13:29
  • 5
    Well, `var x = (Integer) 10;` takes more keystokes than `Integer x = 10;` so I'll stay with the latter probably. – mid Mar 22 '18 at 17:13
11

According to the proposed specification changes in 14.4.1 Local Variable Declarators and Types:

If 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).

In other words, the inferred type for the local variable is the type that the initializer expression would have if it were used as a standalone expression. 42 as a standalone expression has type int, ergo, the variable number is of type int.

Upward projection is a term defined in the spec changes that doesn't apply to simple cases like this.

asgs
  • 3,718
  • 6
  • 36
  • 49
Jörg W Mittag
  • 337,159
  • 71
  • 413
  • 614
7

Let's test it. With jshell:

jshell> Integer boxed1 = 42000;
boxed1 ==> 42000

jshell> Integer boxed2 = 42000;
boxed2 ==> 42000

jshell> System.out.println(boxed1 == boxed2);
false

jshell> var infered1 = 42000;
infered1 ==> 42000

jshell> var infered2 = 42000;
infered2 ==> 42000

jshell> System.out.println(infered1 == infered2);
true

In the first comparison, the two variables are not the same; they're different instances. The second comparison is however true, hence an int must've been infered here.

Note: To try it at home, use values outside <-128, 128). Integer instances in that range are cached.

david a.
  • 5,149
  • 20
  • 23
  • 14
    This is a very roundabout proof. And you're relying on implementation details of the Integer cache... A better proof would be simply `var i = 10` followed by `i instanceof Integer`. You'll get `ERROR: unexpected type` because it's an int and not a reference. – Michael Mar 22 '18 at 11:23
  • 4
    And just FYI, you don't need `System.out.println`. Just evaluate `infered1 == infered2` on it's own. – Michael Mar 22 '18 at 11:24
  • Michael, yeh, I thought of instanceof for a second, but didn't try. I should have :) – david a. Mar 22 '18 at 11:39
  • In general, I like the "proof" by code but for a more general answer, JLS is still better. An implementation can be changed, unless this is written in the JLS. But since i never though about when to use `Jshell`, I like this answer ! – AxelH Mar 22 '18 at 11:39
  • 1
    @AxelH Agree. If an answer is based on empiricism, I'd say you should always state what version you're testing with. – Michael Mar 22 '18 at 11:46
1

The compiler treats var number = 42; similarly to int number = 42;

public void method(Integer i) {
    System.out.print("Integer method");
}
public void method(int i) {
    System.out.print("int method");
}

var n = 42; // n has type 'int' 
method(n); // => "int method"

And auto-boxing when:

public void method(Integer i) {
    System.out.print("Integer method");
}

var n = 42; // a has type 'int'
method(n); // => "Integer method"
tonyhoan
  • 968
  • 6
  • 12