· 3 min read
Operator Overload in Kotlin: Add standard operations to any class (KAD 17)
In Kotlin, as in every language, we have predefined operators to perform certain operations.
The most typical are the addition (+), subtraction (-), multiplication (*) or division (/), but there are a few more.
In some languages, such as Java, these operators are limited to certain types of data, and we have no way to make other types use them.
There are other languages like Scala in which we can invent any type of operator that occurs to us, since the names of the functions accept any symbol.
An intermediate solution is taken in Kotlin: there are a number of predefined operators, but we can overload them for any kind of data.
Operator Overload in Kotlin
As we talked, Kotlin can overload a number of operators, implementing the corresponding function in our class. Esta función debe estar marcada con la palabra reservada operator
.
The operators are basically the following:
Unary Operators
Expression | Function |
---|---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
a++ | a.inc() |
a— | a.dec() |
Binary Operators
Expression | Function |
---|---|
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.times(b) |
a / b | a.div(b) |
a % b | a.mod(b) |
a..b | a.rangeTo(b) |
a in b | b.contains(a) |
a !in b | !b.contains(a) |
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) |
Array Type Operators
Expression | Function |
---|---|
a[i] | a.get(i) |
a[i, j] | a.get(i, j) |
a[i_1, …, i_n] | a.get(i_1, …, i_n) |
a[i] = b | a.set(i, b) |
a[i, j] = b | a.set(i, j, b) |
a[i_1, …, i_n] = b | a.set(i_1, …, i_n, b) |
Equals Operation
Expression | Function |
---|---|
a == b | a?.equals(b) ?: b === null |
a != b | !(a?.equals(b) ?: b === null) |
The equals
operations are a bit different, because they use a more complex translation to do a correct check, and because they expect an exact specification of the function and not just a specific name for it. The function must be implemented exactly like this:
fun equals(other: Any?): Boolean
Invoking Functions
Expression | Function |
---|---|
a(i) | a.invoke(i) |
a(i, j) | a.invoke(i, j) |
a(i_1, …, i_n) | a.invoke(i_1, …, i_n) |
An example
Imagine that you have a data model for companies, each of which has a list of employees.
You could use the get
operator to access the positions using brackets. The implementation is very easy:
class Employee(val id: Long, val name: String)
class Company(private val employees: List<Employee>) {
operator fun get(pos: Int) = employees[pos]
}
And that’s how you could use it:
val company = Company(listOf(Employee(1235, "John"), Employee(2584, "Mike")))
val mike = company[1]
But you could go beyond, and use the id to recover the value, implementing the function like this:
operator fun get(id: Long) = employees.first { it.id == id }
val mike = company[2584]
Conclusion
Operators can help us to improve readability by using common symbols for known operations.
Be careful not to use them in situations where they can lead to confusion to readers, and they can become a really interesting tool.
If you have not already done so, I recommend you to get the free guide to learn how to build your first project, or just get the book and learn how to create a complete App from scratch.