Learning Kotlin: Operators
Note * This is the 17th post in a multipart series. If you want to read more, see our series index.
This next post is an introduction to operators in Kotlin—not the basic "use a plus sign to add numbers together" stuff (you read this blog, you’ve got to be smart enough to figure that out). No, this post is about just how amazingly extensive the language is when it comes to supporting your classes’ use of them.
Adding Things Together
Let’s start with a simple addition example—I did say we wouldn’t do this. In the following code, we track scoring events in a rugby game and want to add them up to get the total score:
enum class scoreType {
`try`, conversion, kick
}
data class score(val type: scoreType) {
fun points() = when (this.type) {
scoreType.`try` -> 5
scoreType.conversion -> 2
scoreType.kick -> 3
}
}
fun main(args: Array<String>) {
val gameData = listOf(
score(scoreType.`try`),
score(scoreType.conversion),
score(scoreType.`try`),
score(scoreType.kick)
)
var totalPoints = 0
for (event in gameData) {
totalPoints += event
}
println(totalPoints)
}
This obviously won’t compile—you can’t add a score and an Int? Right?! We could make this change, which is probably the better way, but for my silly example, let’s say this isn’t ideal:
totalPoints = event.points() + totalPoints
So to make our code compile, we just need a plus function marked with the operator keyword. The Kotlin compiler is smart enough to make it work:
data class score(val type: scoreType) {
fun points() = when (this.type) {
scoreType.`try` -> 5
scoreType.conversion -> 2
scoreType.kick -> 3
}
operator fun plus(other: Int) = this.points() + other
}
How cool is that?! If I wanted to support totalPoints += event further, we’d need to add a function to Int that tells it how to add a score. Thankfully, that’s easy with extension functions:
operator fun Int.plus(other: score) = this + other.points()
Extensive Support
While the above is a bit silly, imagine building classes for distances, time, weights, etc.—being able to have a kilogram and a pound class and add them together! What makes Kotlin shine is how extensive it is. Just look at this list:
| Class | Operators | Method | Example Expression |
|---|---|---|---|
| Arithmetic | +, += | plus | first + second |
| Augmented Assignments | += | plusAssign | first += second |
| Unary | + | unaryPlus | +first |
| Increment & Decrement | ++ | inc | first++ |
| Arithmetic | -, -= | minus | first - second |
| Augmented Assignments | -= | minusAssign | first -= second |
| Unary | - | unaryMinus | -first |
| Increment & Decrement | -- | dec | first-- |
| Arithmetic | *, *= | times | first * second |
| Augmented Assignments | *= | timesAssign | first *= second |
| Arithmetic | /, /= | div | first / second |
| Augmented Assignments | /= | divAssign | first /= second |
| Arithmetic | %, %= | rem | first % second |
| Augmented Assignments | %= | remAssign | first %= second |
| Equality | ==, != | equals | first == second |
| Comparison | >, < | compareTo | first > second |
| Unary | ! | not | !first |
| Range | .. | rangeTo | first..second |
| In | in, !in | contains | first in second |
| Index Access | [, ] | get | first[index] |
| Index Access | [, ] | set | first[index] = second |
| Invoke | () | invoke | first() |
I’ll go through some of these in more detail in future blog posts, but one worth calling out now:
Augmented Assignments vs. plus/minus
You might wonder why implementing plus above gave us support for both + and +=—and why the table lists += under both categories. Why both?
Because you may want to support only += without supporting +.