103

If short is automatically promoted to int in arithmetic operations, then why is:

short thirty = 10 * 3;

A legal assignment to the short variable thirty?

In turn, this:

short ten = 10;
short three = 3;
short thirty = ten * three; // DOES NOT COMPILE AS EXPECTED

as well as this:

int ten = 10;
int three = 3;
short thirty = ten * three; // DOES NOT COMPILE AS EXPECTED

does not compile because assigning an int value to a short is not allowed without casting as expected.

Is there something special going on about numerical literals?

Ceiling Gecko
  • 3,104
  • 2
  • 24
  • 33
  • 23
    `short thirty = 10 * 3;` is most probably replaced by `short thirty = 30;` by the compiler which is a valid statement then. (I'd have to look up the relevant JLS section though). – Thomas Aug 25 '15 at 12:02
  • The compiler calculates `10 * 3` and initializes the variable with the result. In your non-working example the calculation happens at runtime where the JVM casts the short. – Felix Aug 25 '15 at 12:03
  • I think this is a duplicate, of http://stackoverflow.com/questions/30346587/java-char-to-byte-casting or http://stackoverflow.com/questions/9379983/type-casting-of-byte-and-int . However: Note that `final int ten = 10; final int three = 3; short thirty = ten * three;` compiles fine. – Marco13 Aug 25 '15 at 12:46
  • 7
    `If short is automatically promoted to int in arithmetic operations` -- that's not relevant. Neither `10` nor `3` are shorts nor are they promoted, they're literals. – Matthew Read Aug 25 '15 at 18:36
  • @MatthewRead: but even as literals, they have to get evaluated as a particular datatype, right? So is it true that `10` and `3` are evaluated as `int`s by the compiler? – LarsH Aug 26 '15 at 16:31
  • @LarsH - Not always. `short s = 5` and `int i =10` are evaluated as `short` and `int` respectively. The problem comes when we have a *dangling constant*. If `short s = 5;` , then `short s2 = s+5` won't work because the compiler thinks `s+5` would lead to an `int`. If `s` were `final ` (compile time constant), then the compiler knows that `s+5` would fit in a `short` and thus it would be alllowed – TheLostMind Aug 27 '15 at 07:27

3 Answers3

138

Because the compiler replaces 10*3 with 30 at compile time itself. So,effectively : short thirty = 10 * 3 is calculated at compile time.

Try changing ten and three to final short (making them compile time constants) and see what happens :P

Examine byte-code using javap -v for both verisions (10*3 and final short). You will be able to see that there is little difference.

Ok, So, here is the byte code difference for different cases.

Case -1 :

Java Code : main() { short s = 10*3; }

Byte code :

stack=1, locals=2, args_size=1
         0: bipush        30  // directly push 30 into "s"
         2: istore_1      
         3: return   

Case -2 :

public static void main(String arf[])  {
   final short s1= 10;
   final short s2 = 3;
   short s = s1*s2;
}

Byte code :

  stack=1, locals=4, args_size=1
         0: bipush        10
         2: istore_1      
         3: iconst_3      
         4: istore_2      
         5: bipush        30 // AGAIN, push 30 directly into "s"
         7: istore_3      
         8: return   

Case -3 :

public static void main(String arf[]) throws Exception {
     short s1= 10;
     short s2 = 3;
     int s = s1*s2;
}

Byte-code :

stack=2, locals=4, args_size=1
         0: bipush        10  // push constant 10
         2: istore_1      
         3: iconst_3        // use constant 3 
         4: istore_2      
         5: iload_1       
         6: iload_2       
         7: imul          
         8: istore_3      
         9: return 

In the above case, 10 and 3 are taken from the local variables s1 and s2

TheLostMind
  • 35,966
  • 12
  • 68
  • 104
  • 17
    liked `Try changing ten and three to final short` exercise :) – S. Pauk Aug 25 '15 at 12:19
  • 1
    @SergeyPauk - That's really important in understanding compile time constants.. applies to all primitives (Strings as well..) :) – TheLostMind Aug 25 '15 at 12:22
  • 1
    @TheLostMind I would suggest a better wording `you will see that there's no difference (between those two lines in the decompiled code)` cause isn't this your point? – S. Pauk Aug 25 '15 at 12:59
  • 4
    Amusingly, this also means that `case 10*3:` and similar is legal in a switch construct. – Ceiling Gecko Aug 25 '15 at 15:33
  • 5
    And similarly in enum constructs. In fact, using stuff like 1 << 5 for bitfield enum constants is idiomatic. – Bathsheba Aug 25 '15 at 17:18
  • 1
    @CeilingGecko - Yes it is legal. `case i : ` works when `i` is marked as `final short` – TheLostMind Aug 26 '15 at 04:37
18

Yes there is something special going on with the literal case: 10 * 3 will be evaluated at compile time. So you don't need an explicit (short) conversion for multiplied literals.

ten * three is not compile-time evaluable so therefore needs an explicit conversion.

It would be a different matter if ten and three were marked final.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

The following answer adds the JLS section and some details about this behavior.

As per JLS §15.2 - Forms of Expressions

Some expressions have a value that can be determined at compile time. These are constant expressions (§15.28).

Community
  • 1
  • 1
Nicolas Henneaux
  • 11,507
  • 11
  • 57
  • 82