The type of `0` (Implicit narrowing conversion)

31 views
Skip to first unread message

zhong...@gmail.com

unread,
Nov 11, 2015, 3:20:26 PM11/11/15
to java.lang.fans
In Java, the type of a literal is fixed; the type of `0` is always `int`, regardless of context.

Of course, we would also want to use literal `0` in places where other numerical types are expected,
e.g. use `0` as byte or double. Java approaches that problem by performing type conversion.

In general, there is no problem to use an `int` as `long/float/double`;
widening primitive conversion is generally allowed and implicitly carried out.

On the other hand, narrowing primitive conversion ($5.1.3) is very limited; it's performed in

n1. explicit casting, e.g. `(byte)anInt`

n2. ++ and --, e.g. `aByte++`  (increment is done on `int` level)

n3. += etc, e.g. `aByte+=anInt`

n4. when a constant value fits a narrower type, e.g. `byte b=0;`

Let's catalog the places where [n4] applies. It is mostly specified by
assignment conversion ($5.2) which other parts of JLS reference to.

c1. assignment

        byte b = 0;  // int `0` is converted to byte
      
c2. array initializer

        byte[] bs = { 0, 1 };

c3. return

        byte foo(){ return 0; }
      
        (ByteSupplier)()->0
      
c4. switch-case

        switch(aByte){  case 0: }

c5. annotation

        @interface Foo
        {
            byte aByte() default 0;
           
            byte[] aByteArray() default {0,1};
        }

        @Foo( aByte=2, aByteArray={3,4} )

c6. conditional expression

        bool ? 0 : aByte
       
    the type of this expression is `byte`, because constant `0` fits `byte`.
    If we change `0` to `300`, the type of the expression becomes `int`.
   
   
These are all that I can find in JLS-8.   

--
   
[c1-6] only apply for `byte/short/char/int`; they don't apply for `long` etc, for example

    int i = 0L; // does not compile   
   
[c1-6] apply for constant expressions, not just int literals. For example

    byte b = 1 + 1; // ok; equivalent to `byte b=2`
   
This makes sense for simple expressions. If the constant expression becomes more complicated, it gets confusing

    byte b = true ? 0 : 300;  // ok
    // the conditional expr is a constant expression that evaluates to an int `0`
    // therefore the code is equivalent to
    byte b = 0;
   
[c6] only applies if the constant expression is `int`. We don't need to dwell more on it,
the whole conditional expression spec is insane anyway.    
   
---

What's apparently missing among [c1-6] is method invocation

    void foo(byte b){}
   
    foo(0); // error

here `0` is not implicitly converted to `byte`.
See end of $5.3 for justification (complication of method overload resolution).
         
Note also that in `aByte>0`, `0` is not narrowed to a byte; instead, `aByte` is widened to an int. 


Zhong Yu

unread,
Nov 11, 2015, 3:42:47 PM11/11/15
to java.lang.fans
On Wed, Nov 11, 2015 at 2:20 PM, <zhong...@gmail.com> wrote:
[c1-6] only apply for `byte/short/char/int`; they don't apply for `long` etc, for example
   
[c6] only applies if the constant expression is `int`.

For example, [c1-5] allow converting a `short` constant to byte

        byte b = (short)0;

However, [c6] is a completely different animal.

    bool ? (int)0 : aByte    // type is byte

    bool ? (short)0 : aByte  // type is short

Again - I don't think we should should care about this mess. Instead, always use identical statical types in conditional expressions; do explicit casting if necessary.

    bool ? (byte)0 : aByte

    bool ? (short)0 : (short)aByte
Reply all
Reply to author
Forward
0 new messages