Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: What do the unary plus/minus operators do on numbers?

I've noticed in Kotlin that there are already defined unaryPlus and unaryMinus operators on all of the number types.

What's the purpose of these operators? Are they in some way connected to the prefix forms of inc and dec?

like image 763
Jire Avatar asked Sep 09 '16 07:09

Jire


3 Answers

Others have defined the basic meaning of unaryMinus and unaryPlus, and in reality on numeric types they may not actually even be called as functions. For example, coding +x or x.unaryPlus() generates the same bytecode (where x is type Int):

ILOAD 1
ISTORE 2

And the code -x or x.unaryMinus() generates the identical bytecode:

ILOAD 1
INEG
ISTORE 2

But there is more going on that this...

So why does the compiler even generate anything for +x? Some people will say that +x and x.unaryPlus() doesn't do anything, and that -x and x.unaryMinus() only reverses the sign. That isn't correct. In Java it is more complicated because it can involve widening and unboxing, see Unary Numeric Promotion which explains the full consequences of these operators. This has consequences for boxed values and types smaller than Int. For value of type Short and Byte these operators will return a new unboxed value widened of type Int. And since both operators have this more hidden functionality then both must generate bytecode even if you don't think +x does anything. By the way, this is similar to what C language does and it is called Usual Arithmetic Conversions.

Therefore this code is invalid:

val x: Short = 1
val y1: Short = +x              // incompatible types
val y2: Short = x.unaryPlus()   // incompatible types
val z1: Short = -x              // incompatible types
val z2: Short = x.unaryMinus()  // incompatible types

In these numeric cases on the base numeric types they are just compiler magic to allow for the idea of these operators to be equated to operator functions that you might want to overload in other classes.

For other uses such as Operator Overloading...

But they are there for more than just mathematical use and can be used on any class as an operator. Kotlin exposes operators as functions so that you can apply operator overloading on a specific set of operators which include unaryMinus and unaryPlus.

I could use these to define operators for my own or existing classes. For example I have a Set<Things> where Things is an enum class along with an unaryMinus() operator to negate the contents of the finite set of options:

enum class Things {
    ONE, TWO, THREE, FOUR, FIVE
}

operator fun Set<Things>.unaryMinus() = Things.values().toSet().minus(this)

And then I can negate my enum set whenever I want:

val current = setOf(Things.THREE, Things.FIVE)
println(-current)       // [ONE, TWO, FOUR]
println(-(-current))    // [THREE, FIVE]

Notice that I had to declare my extension function with the modifier operator or this will not work. The compiler will remind you if you forget this when you try to use the operator:

Error:(y, x) Kotlin: 'operator' modifier is required on 'unaryMinus' in 'com.my.favorite.package.SomeClass'

like image 55
8 revs Avatar answered Sep 19 '22 21:09

8 revs


These operators are the signs of the integers. Here are some examples:

+5 calls 5.unaryPlus() and returns 5.

-5 calls 5.unaryMinus() and returns -5.

-(-5) calls 5.unaryMinus().unaryMinus() and returns 5.

like image 42
marstran Avatar answered Sep 23 '22 21:09

marstran


The purpose of those operators is to be able to write:

val a = System.nanoTime()
val b = -a // a.unaryMinus()
val c = +b // b.unaryPlus()

They are not directly related to ++/inc and --/dec operators however they can be used in conjunction.

Notice that the following expressions are different:

--a // a = a.dec()
-(-a) // a.unaryMinus().unaryMinus()
like image 35
miensol Avatar answered Sep 19 '22 21:09

miensol