· 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

ExpressionFunction
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()
a++a.inc()
a—a.dec()

Binary Operators

ExpressionFunction
a + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.mod(b)
a..ba.rangeTo(b)
a in bb.contains(a)
a !in b!b.contains(a)
a += ba.plusAssign(b)
a -= ba.minusAssign(b)
a *= ba.timesAssign(b)
a /= ba.divAssign(b)
a %= ba.modAssign(b)

Array Type Operators

ExpressionFunction
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] = ba.set(i, b)
a[i, j] = ba.set(i, j, b)
a[i_1, …, i_n] = ba.set(i_1, …, i_n, b)

Equals Operation

ExpressionFunction
a == ba?.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

ExpressionFunction
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.

    Share:
    Back to Blog