# “K-O-T-L-I-N, a smooth operator overloadin’ correctly!”

Rage Against The Machine* once covered a musing about smooth operators operating correctly.

Here we are going to cover overloading operators and getting them to operate as correctly and smoothly as possible.

**What is operator overloading?**

An **operator** is like a plus sign or a “greater than” sign. You typically think of them in expressions like `1 + 1`

or `3 > 2`

. The operator operates on one or two **operands**. Most vanilla cases involve using numbers and the language already supports that. Even `String`

is somewhat supported:

`val newString = "effec" + "t" // results in "effect"`

“Adding” is simple concatenation. But what happens when we subtract?

`val newString = "effect" - "e" // what is the meaning of this?!`

That won’t compile, in either Java or Kotlin. But let’s say we were writing some program where we had to filter out single characters from text frequently. It might be nice to have the ability to express that function simply as:

`val newString = "effect" - "e" // "ffct"`

or:

`val newString = "team" - "I" // "team" because there is no...`

Kotlin associates certain **reserved** function names like `plus`

and `minus`

to syntactically corresponding (usually intuitive) operators. Here’s how you would overload the minus operator for strings in Kotlin, for the functionality intended above:

`operator fun String.minus(filterOut: String): String {`

return this.*replace*(filterOut, "")

}

This is kind of a dirty trick but it works. If we didn’t have ability to use the literal minus sign, we’d have to write:

`val newString = "team".minus("I") // ugh, low rent`

What we have now is an extension function that works on Strings except it has the keyword `operator`

in front of the signature. We’re forced to implement this as a top-level extension function because we can’t add this operator overload within the `String`

system class itself, but that’s okay.

Overloading operators as class members is preferable. Here’s a somewhat non-obvious example for an overloaded operator:

`interface Pet`

class Dog : Pet

class Cat : Pet

class Scoop<T : Pet>(val scoops: Int) {

operator fun plus(other: Scoop<T>) = Scoop<T>(this.scoops + other.scoops)

}

val dogFood = Scoop<Dog>(1) + Scoop<Dog>(2)

*println*("scoops of dog food: ${dogFood.scoops}")

This is will print `scoops of dog food: 3`

.

Above, the operator is overloaded as a member of the class of the objects it acts on. This makes the code cleaner and the logic easier to contain. But all we’ve done so far is just thinly wrap the idea of adding integers- I mean, *big whoop*, right? Notice a subtle benefit though: we don’t want to mix dog food and cat food together and the generic bound on our plus operator prevents such violations from even compiling!

`val grossFood = Scoop<Dog>(1) + Scoop<Cat>(2) //won't compile!`

If `Scoop`

wasn’t typed and perhaps instead each object had a `val`

that held an `enum`

type value of either `DOG`

or `CAT`

and we still wanted to enforce not mixing/adding different types of food, we’d have to do something *really dumb* like check the type field inside the overloaded operator function and throw a runtime exception if someone was trying to add different types. That might’ve flown if you were a Java developer in 2007, but those days are over, kid.

The point of this is not to do a diverted tour of generics, it is to get you thinking about the *meaning* of overloading an operator.

Sorry I sort of threw in a curveball on generics there. Actually I’m not sorry. I’m going to throw in one more because I can’t help myself. Let’s answer the age old question:

`println("Dogs better than cats? ${Dog() > Cat()}")`

Right now, this won’t compile. And don’t ever write strings like this where you are initializing objects inline unless you want to get violently thrown out of a job interview. But I digress.

We need to overload the “greater than” sign. In the `plus`

overload we did, the *meaning* of the function availed itself easily. We’re adding scoops of pet food. Even if we wanted to produce the most complicated addition algorithm ever- like, say, looking at each scoop by the number of individual kibbles- we know that the *contract* of the addition function is straightforward: take in two Scoop objects, output one Scoop object. The contract doesn’t care how we get there, just that we do.

“Greater than” and the other comparison signs are different. They don’t return objects of the same type- they return `true`

or `false`

. Although you should never compare yourself to others, you’re going to have to now and Kotlin demands you tell it exactly how you stack up against everyone of your peers by implementing the `Comparable<T>`

interface.

`interface Pet : Comparable<Pet>`

class Dog : Pet {

override fun compareTo(other: Pet): Int = if (other is Cat) 1 else 0

}

class Cat : Pet {

override fun compareTo(other: Pet): Int = if (other is Dog) -1 else 0

}

Here’s our updated class definitions. For the sake of silly examples in a tutorial blog it is sufficient to tell you that `compareTo()`

needs to return a positive number (1) for “this is greater than that”, zero (0) for “this is equal to that”, and a negative number (-1) for “this is less than that.”

So `Dog() > Cat()`

will call the comparison function on the Dog object with Cat as `other`

. Kotlin reads the terms in order from left to right, so if you wanted the Cat’s comparison function to be called with Dog as the `other`

, you’d have to write `Cat() > Dog()`

(which would return `false`

). Any operator that you overload should honor the associative and commutative properties you learned in 6th grade. You should be able to swap and regroup terms and equivalent expressions should evaluate to equivalent values.

We’ve gone ahead and hardcoded the correct universal values for differences between dogs and cats.

`println("Dogs better than cats? ${Dog() > Cat()}") //true, of course`

It’s silly, but take a nontrivial example of sorting colors into a rainbow. Your `Color`

class will implement `Comparable<Color>`

. You’d probably be doing some math on the RGB values to find the color’s light wavelength, and then do a comparison on the `Double`

values of wavelengths of the two colors. That logic would be taking place inside your `compareTo()`

.

One thing to keep in mind is that while the meaning of numerical operations tends to be narrow, there can often be many meaningful ways to *compare* objects of the same type. If you choose to implement `Comparable<T>`

be careful what aspect of your objects you choose to compare. It will forever be tied to any expressions you write with `< > => =< `

signs.

(side note: when you write `obj1 > obj2`

Kotlin calls `obj1.compareTo(obj2)`

under the hood and essentially evaluates something like `result > 0`

to return `true`

or `false`

for the expression)

**A Finer Point**

Not all operators take in two things and output another thing, whether it be an object of the same type or `true`

or `false`

. Some operators expect you to alter the one operand object in question. Consider the following:

`var a = 1`

a += 3

// a == 4

The `plusAssign`

operator, or `+=`

can be overloaded. Let’s look at our Scoop class:

`class Scoop<T : Pet>(val scoops: Int) {`

operator fun plusAssign(other: Scoop<T>): Unit {

this.scoops += other.scoops //UH OH!!

}

}

Oh no! Iceberg straight ahead! Our `scoops`

count is an immutable `val`

. That means that the meaningful information we wish to change can’t be changed in the original Scoop object. With our overloaded `plus`

function we can return that new state into a new Scoop object but here we are borked. Unless we change the `scoops`

member to a `var`

, we’ll never be able to use `plusAssign`

in this way. Objects with **immutable** state are usually better if you have a choice, so if changing a property to a `var`

would violate design decisions in the rest of your app then you simply don’t need `plusAssign`

.

Overloaded operators are there for us to express things we do to objects in a clearer and concise way. Our motivation should always be to overload operators to get rid of verbose code, repeated code, and boilerplate. We don’t overload all the operators first just to see what kind of interesting things we can make happen (although it is fun). Another place we can overload operators is when we find ourselves mixing objects with function names that sort of hint at an operation. An example of this would be:

`val newString = "123".repeat(3) // "123123123"`

If String`plus`

is already concatenate, why not make `times`

a “repeat”?

operator fun String.times(n: Int) = this.repeat(n)val newString = "123" * 3 // "123123123"

This is nice, but you probably wouldn’t want to do this unless you were making repeated strings *a lot *in your app. And I mean, *a lot*. A good way to think about it is if another developer came fresh to your code, their momentary confusion is justified if repeating String concats is something you’ve done all over the place and it’s impossible to miss. It’s probably not justified to overload operators for just little expressions “here and there.”

Also, above, note that we overloaded the meaning of the operator *for an operand of a different type*. Namely, the integer operand for number of repeats is not a String. There is no restriction on mixing (and overloading) types like this. You just have to make sure that what you’re doing makes sense in the human world.

**Make your own operators!**

It’s true! You can make your own operators. There is some fine print, though.

`infix fun Scoop.spill(percent: Double) = Scoop((this.scoops * percent).`*roundToInt*())

I’ve removed the generic typing of the `Scoop`

class you saw earlier for the sake of this example. Aside from the `infix`

keyword, this is a normal, everyday extension function. When you’re scooping up your pet food for din din time but you accidentally `spill`

some `percent`

of it on the floor, this function tells you how many countable scoops you have left.

`val regularScoop = Scoop(scoops = 4)`

val sadScoop = regularScoop.spill(percent = 0.5)

That’s using the extension function the usual way. But that `infix`

keyword lets us write this instead:

`val sadScoop = regularScoop spill 0.5`

That’s “infix notation.” There are rules that come with this. The function name can’t be a reserved operator, it must always operate on two operands, and some other rules. Resist the temptation to use garden variety functions as operators. Let’s say, as a **bad example**, you had some logic to increment the number of scoops of food because your pet is staring at you and workin’ you hard:

`val newScoop = regularScoop petStaringAtMe true`

If you made an `infix`

function of that name that took a `Boolean`

then that would be perfectly legitimate code. The problem with that is when you try to understand the “philosophical” meaning when reading it. Consider:

`val sadScoop = regularScoop spill 0.5`

val newScoop = regularScoop petStaringAtMe true

The first statement almost reads as English. “Take a regular scoop, which is 4 scoops, and spill 50 percent of it.” The second statement, although it makes English sense, *isn’t very clear what petStaringAtMe actually does*. It almost feels like we’re setting a property and we shouldn’t be using infix notation for that. A fresh developer would have to go read the implementation details to understand that and that strikes me as code smell. Consider:

`7 * 9 * 11 * 13`

We may not be able to do this in our heads but we know at a very quick glance what’s being done to what and what type of the result it will be and where it will be at the end, because we understand how multiplication works. The operators you overload or use in infix notation should work the same way.

**Good grief, that’s not the end?**

**No.** I’m just working up to the great, wondrous, real world example of overloaded operators in Kotlin. And grab your 5th cup of coffee, because I’m going to talk about math.

In hardware sensors that give you information about the movement in the real world the information is often given in structures with 3 values. These values usually correspond to X, Y, and Z dimensions in 3D space. The **type** of value could be different: acceleration, rate of rotation, magnetic field vectors (a.k.a. fancy compass), etc.. Enter the vector:

`data class Vector(val x: Double, val y: Double, val z: Double)`

What we’re representing as a `data class`

is a vector: a mathematical object that is basically an arrow that points in a direction and has a magnitude, or it can mean a coordinate in space (technically those are the same thing but I’ll move on ‘cuz y’all didn’t come here for my TED Talk).

When we capture values out of a live, real world stream of information it is best we stuff those values into our immutable `Vector`

s. If you wanted to calculate your absolute orientation in space you will have to combine 3D vectors from several different sensors and then *math the shit out of them*. I’m talking rotations, scalings, averages, translations, etc. I’m talking reading from foreign hardware so we’re gonna need some bit shifting or byte swapping. I’m talking deep queues of samples for low pass filtering. Woo!

I took some old C++ code for a driver written for an orientation chip known as an MPU9255. This code works, but it’s a little… busy… as C++ can get:

`// Now we'll calculate the accleration value into actual g's`

ax = MPU9250Data[0]*aRes - accelBias[0]; // get actual g value, this depends on scale being set

ay = MPU9250Data[1]*aRes - accelBias[1];

az = MPU9250Data[2]*aRes - accelBias[2];

// Calculate the gyro value into actual degrees per second

gx = MPU9250Data[4]*gRes; // get actual gyro value, this depends on scale being set

gy = MPU9250Data[5]*gRes;

gz = MPU9250Data[6]*gRes;

MPU9250.readMagData(magCount); // Read the x/y/z adc values

// Calculate the magnetometer values in milliGauss

// Include factory calibration per data sheet and user environmental corrections

mx = magCount[0]*mRes*magCalibration[0] - magBias[0]; // get actual magnetometer value, this depends on scale being set

my = magCount[1]*mRes*magCalibration[1] - magBias[1];

mz = magCount[2]*mRes*magCalibration[2] - magBias[2];

mx *= magScale[0];

my *= magScale[1];

mz *= magScale[2];

What this C++ code is doing is taking values from an accelerometer, gyroscope, and a magnetometer and adjusting the raw read values by some calibration and offset values which have already been calculated. These values next get put into a Madgwick filter, but that story is for another day.

We can see the C++ author is using arrays to store the values for the x, y, and z axes. We also see that how the axes correlate to the element’s position in the array stays consistent. We also see that the operations on each axis value are the same, repeated identically for all 3 dimensions. Hmmm… maybe we could streamline some of this?

We know that the `MPU9250Data[]`

and `magCount[]`

arrays are holding the freshest reads from the chip. These arrays are of `Double`

precision type. With a little shuffling behind the scenes, we can start to corral things in Kotlin:

`val accelData: Vector = mpu9255.readAccelData()`

val gyroData: Vector = mpu9255.readGyroData()

val magData: Vector = mpu9255.readMagData()

…where `mpu9255`

is the chip driver, and we’ve done some low-effort refactoring to the driver class to return the triplet values in a `Vector`

from those read functions. Eventually, we need to do some math and put the results in these:

`//the outputs`

val accel: Vector //accelerometer

val gyro: Vector //gyroscope

val mag: Vector //magnetometer

Looking back at the C++ code, it looks like the author is taking the accelerometer raw data (now in our `Vector`

) and multiplying the components by a single value (a scalar) and then subtracting x, y, z “bias” values. The magnetometer has some additional transformation vectors, so let’s declare:

`val accelBias = Vector(..., ..., ...) //Double values for x y z`

val magBias = Vector(..., ..., ...)

val magFactoryCalibration = Vector(..., ..., ...)

val magScale = Vector(..., ..., ...)

These are basically constants so the actual values don’t matter for this example.

If we wrote a statement multiplying a `Vector`

by a single number it would currently produce a compiler error. Let’s show Kotlin what we want it to do:

`data class Vector(val x: Double, val y: Double, val z: Double) {`

operator fun times(other: Double) = Vector(x * other, y * other, z * other)

}

We’re saying to return a new `Vector`

with each of the `this`

's components acted upon individually by the `other`

scalar value. Simple, no? We’re doing nothing different than regular math except we want Kotlin to handle our “grouping” of numbers as one “thing” in our math expression.

Where `accelScalar`

is a single `Double`

value, previously `aRes`

in the C++ code, now this will fly:

`accel = accelData * accelScalar //ex: (2, 4, 6) = (1, 2, 3) * 2`

But looking at the original C++ code we see we still have to subtract another “bias” `Vector`

for the accelerometer:

`accel = accelData * accelScalar - accelBias //won't compile yet!`

We must overload `minus`

but this time with an operand of the same type:

`data class Vector(val x: Double, val y: Double, val z: Double) {`

operator fun times(other: Double) = Vector(x * other, y * other,

z * other)

operator fun minus(other: Vector) = Vector(x - other.x, y - other.y, z - other.z)

}

Here we act on the components of both `this`

Vector and the `other`

Vector to produce a new `Vector`

. Side note to keep in mind: these overloaded operators are the same as plain old public member functions of this class.

Now we can look at:

`accel = accelData * accelScalar - accelBias`

… and easily say, in English, “take the latest raw 3D data read, scale it by some factor, and the subtract some 3D bias offset, and store the result in a new `Vector`

(`accel`

) .” When we overload all the mathematical operations for all necessary types we are able to turn this:

`// Now we'll calculate the accleration value into actual g's`

ax = MPU9250Data[0]*aRes - accelBias[0]; // get actual g value, this depends on scale being set

ay = MPU9250Data[1]*aRes - accelBias[1];

az = MPU9250Data[2]*aRes - accelBias[2];

// Calculate the gyro value into actual degrees per second

gx = MPU9250Data[4]*gRes; // get actual gyro value, this depends on scale being set

gy = MPU9250Data[5]*gRes;

gz = MPU9250Data[6]*gRes;

MPU9250.readMagData(magCount); // Read the x/y/z adc values

// Calculate the magnetometer values in milliGauss

// Include factory calibration per data sheet and user environmental corrections

mx = magCount[0]*mRes*magCalibration[0] - magBias[0]; // get actual magnetometer value, this depends on scale being set

my = magCount[1]*mRes*magCalibration[1] - magBias[1];

mz = magCount[2]*mRes*magCalibration[2] - magBias[2];

mx *= magScale[0];

my *= magScale[1];

mz *= magScale[2];

… into this!

`accel = accelData * accelScalar - accelBias`

gyro = gyroData * gyroScalar

mag = (magData * magScalar * magFactoryCalibration - magBias) * magScale

It’s so clear you don’t even need the comments! The business logic in each line is entirely literal! We’re expressing *how* we are transforming our raw data to calibrated data, before we pass it on to the next step in the big fancy algorithm. You can’t even tell what variables are `Vector`

and which are single value `Double`

, and maybe that’s kind of the point! Now there’s zero chance of bugs coming from misplacing an array index number, or a typo of a `*`

getting changed to a `+`

in the cluttered sea of C++ expressions!

Here’s the real `Vector`

class I wrote for this particular application:

`data class Vector(val x: Double, val y: Double, val z: Double) {`

constructor(list: List<Double>) : this(list[0], list[1], list[2])

constructor(array: DoubleArray) : this(array[0], array[1], array[2])

val list = *listOf*(x, y, z)

val array = *doubleArrayOf*(x, y, z)

companion object {

val ZeroVector = Vector(0.0, 0.0, 0.0)

val NonZeroVector = Vector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE)

}

fun toVectorInt() = list.*map*(Double::roundToInt).*toVectorInt*()

override fun toString() = "x: $x\t\ty: $y\t\tz: $z"

val quaternion: Quaternion

get() {

// yaw (Z), pitch (Y), roll (X)

// Abbreviations for the various angular functions

val cy = *cos*(z * 0.5)

val sy = *sin*(z * 0.5)

val cp = *cos*(y * 0.5)

val sp = *sin*(y * 0.5)

val cr = *cos*(x * 0.5)

val sr = *sin*(x * 0.5)

return Quaternion(

w = cy * cp * cr + sy * sp * sr,

x = cy * cp * sr - sy * sp * cr,

y = sy * cp * sr + cy * sp * cr,

z = sy * cp * cr - cy * sp * sr)

}

operator fun times(other: Double) = Vector(x * other, y * other, z * other)

operator fun minus(other: Double) = Vector(x - other, y - other, z - other)

operator fun plus(other: Double) = Vector(x + other, y + other, z + other)

operator fun div(other: Double) = Vector(x / other, y / other, z / other)

operator fun rem(other: Double) = Vector(x % other, y % other, z % other)

operator fun times(other: Int) = other.toDouble().*let ***{ **value **-> **Vector(x * value, y * value, z * value) **}**

operator fun minus(other: Int) = other.toDouble().*let ***{ **value **-> **Vector(x - value, y - value, z - value) **}**

operator fun plus(other: Int) = other.toDouble().*let ***{ **value **-> **Vector(x + value, y + value, z + value) **}**

operator fun div(other: Int) = other.toDouble().*let ***{ **value **-> **Vector(x / value, y / value, z / value) **}**

operator fun rem(other: Int) = other.toDouble().*let ***{ **value **-> **Vector(x % value, y % value, z % value) **}**

operator fun times(other: Vector) = Vector(x * other.x, y * other.y, z * other.z)

operator fun minus(other: Vector) = Vector(x - other.x, y - other.y, z - other.z)

operator fun plus(other: Vector) = Vector(x + other.x, y + other.y, z + other.z)

operator fun div(other: Vector) = Vector(x / other.x, y / other.y, z / other.z)

operator fun rem(other: Vector) = Vector(x % other.x, y % other.y, z % other.z)

fun scale(factor: Double) = this * factor //shorthand for times

fun scale(vector: Vector) = this * vector //shorthand for times

fun averageOfComponents() = (x + y + z) / 3

fun unit() = this / *sqrt*(x * x + y * y + z * z)

operator fun get(i: Int): Double =

when (i) {

0 -> this.x

1 -> this.y

2 -> this.z

else -> throw IndexOutOfBoundsException()

}

fun transform(transform: (Double) -> Int) = VectorInt(transform(x), transform(y), transform(z))

fun transform(transform: (Double) -> Double) = Vector(transform(x), transform(y), transform(z))

fun any(predicate: (Double) -> Boolean) = list.*any*(predicate)

fun all(predicate: (Double) -> Boolean) = list.*all*(predicate)

}

There’s obviously more here but one thing we didn’t consider in this tutorial example is when you want to multiply a `Vector`

by an `Int`

scalar instead of a `Double`

. You do have to manually add those overloaded operators with operands of type `Int`

, but it is no different than what we did with the `Double`

one. It can be a bit boilerplate-y but overloading operators can be very worth it!

*yes, I’m aware it is a cover, thank you