Kotlin Operator Overloading

Operator Overloading

Kotlin has a feature called operator overloading. It extends existing operators so they can also be used with other forms. For example, if there is a class that represents numbers, you may want to add or multiply instances of that class. Operator overloading lets you write this as a + b using an operator instead of calling a method directly.

Operators correspond to methods with specific signatures. The + operator can be used by defining a method with a signature such as fun plus(myInt: MyInt): MyInt. In other words, by defining operator methods such as plus() and minus(), you can define operators such as + and -.

To explain this clearly with a concrete example, define a MyInt class as follows. It is a simple class with only one Int value.

Example: MyInt class with the plus method defined

class MyInt(val value: Int) {
    fun plus(myInt: MyInt): MyInt =
         MyInt(value + myInt.value)
}

Using the plus method, you can add another MyInt object to the current object. This plus method also makes it possible to use the + operator.

Example: The + operator can be used

// Method call style
val sum = MyInt(3).plus(MyInt(5))
println(sum.value) // => 8

// Operator style
val sum2 = MyInt(2) + MyInt(7)
println(sum2.value) // => 9

Operator Extension Functions

The following shows another interesting example. Methods corresponding to operators can also be defined as extension functions. Below, plusAssign is added to StringBuilder as an extension function. This plusAssign method corresponds to the += operator.

Example: Extension function corresponding to the += operator

fun StringBuilder.plusAssign(any: Any) {
  append(any)
}

Listing 29 The += operator can be used

val sb = StringBuilder()
sb += "I"
sb += " am"
sb += " Taro"
println(sb) // => I am Taro

Other Operators and Their Method Signatures

Operators and operator method signatures are as follows.

a + b          a.plus(b)
a - b          a.minus(b)
a * b          a.times(b)
a / b          a.div(b)
a % b          a.rem(b)  // Changed from mod() to rem()
a += b         a.plusAssign(b)
a -= b         a.minusAssign(b)
a *= b         a.timesAssign(b)
a /= b         a.divAssign(b)
a %= b         a.modAssign(b)
+a             a.unaryPlus()
-a             a.unaryMinus()
!a             a.not()
++a            a.inc()
--a            a.dec()
a == b         a?.equals(b) ?: (b === null)
a != b         !(a?.equals(b) ?: (b === null))
a < b          a.compareTo(b) > 0
a > b          a.compareTo(b) < 0
a <= b         a.compareTo(b) >= 0
a >= b         a.compareTo(b) <= 0
!var           a.not()
a..b           a.rangeTo(b)
a in b         a.contains(b)
a !in b        !a.contains(b)
a[i]           a.get(i)
a[i, j]        a.get(i, j)
a[i] = b       a.set(i, b)
a[i, j] = b    a.set(i, j, b)
a()            a.invoke()
a(i)           a.invoke(i)
a(i, j)        a.invoke(i, j)

References