46

I understand why the following is wrong:

byte a = 3; byte b = 8; byte c = a + b; // compile error 

It won't compile. Expressions always result in an int. So we should have done the explicit cast:

byte c = (byte) (a + b); // valid code 

But I don't understand why the following is correct:

byte d = 3 + 8; // it's valid! why? 

Because literal integer (such as 3 or 8) is always implicitly an int. And int-or-smaller expressions always result in an int too. Can anybody explain what is going on here?

The only thing I can guess is that the compiler equates this expression to the following:

byte d = 11; 

and doesn't consider this an expression.

3
  • 1
    Given the registers are 32-bit or 64-bit, I would wonder why you are using byte in the first place. Commented Jun 14, 2013 at 14:44
  • byte c = a + b;, because it doesn't fit in byte. Commented Jun 14, 2013 at 14:44
  • 6
    @RongNK: No, that's wrong. It's because a + b evaluates to an int, and the compiler doesn't permit implicit narrowing conversions of non-constant expressions. Commented Jun 14, 2013 at 15:31

3 Answers 3

47

This has less† to do with whether or not 3 + 8 is evaluated to 11 at compile-time, and more to do with the fact the compiler is explicitly permitted to implicitly narrow ints to bytes in certain cases. In particular, the language specification explicitly permits implicit narrowing conversions to byte of constant expressions of type int that can fit in a byte at compile-time.

The relevant section of the JLS here is section §5.2:

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

  • 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.

The compile-time narrowing of constants means that code such as: byte theAnswer = 42; is allowed. Without the narrowing, the fact that the integer literal 42 has type int would mean that a cast to byte would be required:

†: Obviously, as per the specification, the constant expression needs to be evaluated to see if it fits in the narrower type or not. But the salient point is that without this section of the specification, the compiler would not be permitted to make the implicit narrowing conversion.

Let's be clear here:

byte a = 3; byte b = 8; 

The reason that these are permitted is because of the above section of the specification. That is, the compiler is allowed to make the implicit narrowing conversion of the literal 3 to a byte. It's not because the compiler evaluates the constant expression 3 to its value 3 at compile-time.

Sign up to request clarification or add additional context in comments.

5 Comments

@Paul Bellora: I'm sorry you feel that way; I'm not intending to be combative. Please help me understand how I can come across not that way?
While your answer is super-helpful, it seems specifically designed to take down the other existing answer. Ideally, they would've simply supported one another, one with examples, the other with JLS citations. I try to keep my downvotes constructive, but in this case I just found the tone very distracting, so I felt like no vote with a comment was a good compromise.
@Paul Bellora: No, that is not my intention at all, genuinely. :-(
+1. This must be why the compiler, instead of just compiling the code, is also doing some calculations.
Well, the compiler being able to calculate the exact value is one of the preconditions to allowing the conversion. So I'd say it has a lot to do with this.
41

The only thing I can guess is that the compiler equates this expression to the following:

Yes it does. As long as the right side expression is made of constants (which fit into the required primitive type -- see @Jason's answer for what the JLS says about this exactly), you can do that. This will not compile because 128 is out of range:

byte a = 128; 

Note that if you transform your first code snippet like this:

final byte a = 3; final byte b = 8; byte c = a + b; 

it compiles! As your two bytes are final and their expressions are constants, this time, the compiler can determine that the result will fit into a byte when it is first initialized.

This, however, will not compile:

final byte a = 127; // Byte.MAX_VALUE final byte b = 1; byte c = a + b // Nope... 

The compiler will error out with a "possible loss of precision".

14 Comments

It's not correct. It has nothing to do with whether or not 3 + 8 is evaluated to 11 at compile-time. It's because the language specification clearly states that constants expressions of type int that can fit in a byte may be implicitly narrowed to byte at compile-time.
@fge: Read what I quoted from the specification. It explicitly states that the value of the constant expression must be re presentable in the narrower type. In bold in my answer.
@Jason You missed the "and the value of the constant expression is representable in the type of the variable." so it is relevant that 3 + 8 evaluates to 11 and not to, say, 128.
@Jason Can you specifically quote the part of this answer that's incorrect? I'm having trouble following you. "As long as the right side expression is made of constants" seems to be in line with your JLS citation.
@Paul Bellora: Because without the section of the specification that I drew attention to, an explicit cast would be required. It's the section of the specification that I quoted that explicitly permits the implicit narrowing conversion.
|
1

It is because 3 and 8 are compile time constants.

Therefore, at the time of compilation happens, compiler can identify that 3 + 8 can fit into a byte variable.

If you make your a and b to final (constant) variable. a + b will become a compile time constant. Therefore, it will compile without any issue.

 final byte a = 3; final byte b = 8; byte c = a + b; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.