In order to understand why the assignment type-conversion works whilst the invocation one is rejected, one has to refer to the Java Language Specification topic for both narrowing primitive conversions and the context of that conversion: assignment context and invocation context.
According to the JLS, the narrowing primitive conversion is allowed in assignment context if:
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
... which matches your case with int
constant 5
when assigned to short a
.
No such narrowing primitive conversion is allowed in the invocation context, which explains why your call to setNum(short)
fails when passed the int
constant 5
.
But why if the compiler knows I'm passing a constant that a short can hold (as in the assignment) it doesn't let it compile? I mean, what is the difference between them?
The JLS must not have wanted to burden compilers with this additional logic. In the invocation case, the argument which is type-matched to the formal parameter is an expression - the compiler already has to determine the type, but it shouldn't need to also check if the expression's value can also safely be narrowed. In this case, being a constant, it is clear to us that it can be, but in execution context the compiler is allowed to not bother with that check, and is in-fact correct to disallow it.
It should be fairly clear that when expressions are allowed, it would be much easier for bugs to creep in where narrowing cannot be done without losing precision, so the JLS and compilers just disallow it in all cases.
The same is true in numeric context, so the declaration:
short a = 5;short b = a * 5;
... is similarly not allowed, despite being clearly comprised of constants which narrow correctly.
5
can be read as ashort
literal when parsing, whereas in the second example the parser doesn't know the type of the method argument, so it defaults to being parsed as anint
literal. – Henbaneshort x = 1;
, the JLS will let you avoid some casts even though the literal value is anint
. However in all other situations, such as calling a method, there is no syntactical abbreviation allowed. – Cohbertint[] x = {1,2,3};
, but if you create a new array as a value then you must be explicit, likefoo(new int[]{1,2,3});
– Cohbert