Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are in-range narrowed long values not implicitly converted?

When we declare a static final, the Java compiler (or pre-compiler?) seems smart enough to detect out-of-range numbers:

public class Test {
    // setup variables:
    public static final int i_max_byte = 127;
    public static final int i_max_byte_add1 = 128;
    public static final int i_max_short = 32767;
    public static final int i_max_short_add1 = 32768;
    public static final int i_max_char = 65535;
    public static final int i_max_char_add1 = 65536;
    public static final char c_max_byte = 127;
    public static final char c_max_byte_add1 = 128;
    public static final char c_max_short = 32767;
    public static final char c_max_short_add1 = 32768;
    public static final short s_min_char = 0;
    public static final short s_min_char_sub1 = -1;
    public static final short s_max_byte = 127;
    public static final short s_max_byte_add1 = 128;

    // all these are OK:
    public static final byte b1 = i_max_byte;
    public static final byte b2 = s_max_byte;
    public static final byte b3 = c_max_byte;
    public static final byte b4 = (short) i_max_byte;
    public static final byte b5 = (char) i_max_byte;
    public static final char c1 = i_max_char;
    public static final char c2 = s_min_char;
    public static final short s1 = i_max_short;
    public static final short s2 = c_max_short;

    // pre-compiler complains "type-mismatch":
    public static final byte _b1 = i_max_byte_add1;
    public static final byte _b2 = s_max_byte_add1;
    public static final byte _b3 = c_max_byte_add1;
    public static final byte _b4 = (short) i_max_byte_add1;
    public static final byte _b5 = (char) i_max_byte_add1;
    public static final char _c1 = i_max_char_add1;
    public static final char _c2 = s_min_char_min_us1;
    public static final short _s1 = i_max_short_add1;
    public static final short _s2 = c_max_short_add1;
}

The code above proves that for int, short, and char values, the compiler only complains when the value is out-of-range for the type of the assigned variable.

However for long values, the compiler complains even when the numbers are within range:

public class Test2 {
    public static final long l_max_byte = 127;
    public static final long l_max_byte_add1 = 128;
    public static final long l_max_char = 32767;
    public static final long l_max_char_add1 = 32768;
    public static final long l_max_short = 65535;
    public static final long l_max_short_add1 = 65536;
    public static final long l_max_int = 2147483647;
    public static final long l_max_int_add1 = 2147483648L;

    // "type-mismatch" for all:
    public static final byte b1 = l_max_byte;
    public static final byte b2 = l_max_byte_add1;
    public static final char c1 = l_max_char;
    public static final char c2 = l_max_char_add1;
    public static final short s1 = l_max_short;
    public static final short s2 = l_max_short_add1;
    public static final int i1 = l_max_int;
    public static final int i2 = l_max_int_add1;
}

Why is the compiler only smart at range-detection for int, short, and char values?

Why doesn't the compiler do range-detection for long values?

like image 956
Pacerier Avatar asked Oct 20 '22 02:10

Pacerier


1 Answers

The answer may not be satisfactory, but...

The Java Language Specification, Section 5.2, says:

Assignment contexts allow the value of an expression to be assigned (§15.26) to a variable; the type of the expression must be converted to the type of the variable.

...

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.

For the cases that compile fine, the constant expression is always of type short, char, or int, and the value is representable in the target type. For the long type, such a conversion is simply not allowed according to the specification.


The answer may not be satisfactory, because the next obvious question is:

Why did they write the specification like that?

This may partially be answered by the example that is also given in the linked section of the JLS: This implicit conversion is most likely mainly intended for the case that you want to write a declaration like

byte b = 42;

because otherwise, you would have to cast the int value 42 to byte like in

byte b = (byte)42;

The case that you want to initialize a byte from a long value is just not so common in this sense.

like image 119
Marco13 Avatar answered Oct 22 '22 16:10

Marco13