unaryPlus/Minus and Byte and Short


#1

Why do unaryPlus and unaryMinus return Int instead of Byte/Short for Byte/Short?
(E.g. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-short/unary-minus.html)

I understand it for plus/minus/etc. but why for unaryPlus/Minus?

fun foo(b: Byte) = +b

will never overflow/underflow the Byte.

For reference, inc and dec return Byte/Short even though they might actually over/underflow.


#2

It will be for consistency with Java whose unary operators behave in exactly the same way.

I’m not sure about the reason for this though you would have a problem applying unary negation to a Byte value of -128 or a Short value of -32768 given that there’s no corresponding positive value within the range of those types.


#3

Uh right I totally missed the -BYTE_MIN and -SHORT_MIN cases. The same objection doesn’t really hold for unaryPlus but I guess then it’s a matter of consistency.


#4

This is a JVM feature, Kotlin has to obey it.
JVM provides no bytecode to apply arithmatic operations to byte and short type.
In fact, JVM can only do arithmatic operations on four primitive types: int, long, float and double.

Before arithmatic operation on other primitive types, Java compiler or JVM will extend it to int type number:

  • byte & short -> Signed-Extend -> int
  • char & boolean -> Zero-Extend -> int

Because of this , int is the Computational Type of byte, short, char and boolean.

Example:

// Java code
short s = 200; // 200 to avoid iconst_* and bipush
System.out.println(-s);

bytecode:

sipush 200    -> Push short number 200 to stack's top
istore_1    -> store this number as int into slot 1
getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream
iload_1    -> load 200 as int from slot 1
ineg    -> apply unary minus on 200
invokevirtual #3 // Method java/io/PrintStream.println:(I)V

It’s clear that before do unary minus on short number 200, 200 is extended to int.