Code expressivity++ with operator overloading

Kotlin Vocabulary

Meghan Mehta
Android Developers

--

When we work with types that can be added, removed, compared, or concatenated we end up with verbose code that we need to write again and again. In Kotlin, we can write more expressive and concise code for these types with the help of operator overloading.

One thing I love as much as I love Android is singing in a choir, so let’s use an example of a choir of singers to illustrate the benefits of operator overloading. Let’s say that we have a choir of singers and we want to add another singer to our choir. We would write code that looks like this:

And we would add a new Singer, like this:

choir.addSinger(singer)

But this kind of operation lends itself better to the += operator, so calling this would feel more natural:

choir += singer

Read on to find out:

  • How to implement this in Kotlin with operator overloading.
  • What kind of operators are available to implement and where you can already take advantage of them in Android.
  • Best practices to be aware of when writing your own operators.
  • What the Kotlin compiler does under the hood.

Operator overloading basics

With operator overloading, you can provide implementations for a predefined set of operators on any type. Operators are overloaded either through member functions or through extension functions that use the corresponding member functions. For example, the + operator can be overloaded through the plus() function and the += operator can be overloaded through the plusAssign() function. Note that operators do not chain: if you overload +, ++ will not also be taken care of.

To overload an operator you will need to use the operator keyword before fun and then specify which operator you would like to overload. If you do not use the operator keyword, the compiler will treat this as a regular Kotlin function and won’t even compile!

Here are the operators you can overload in Kotlin:

For a full list of operators that can be overloaded and their corresponding functions, see here.

How to do it

Alright, let’s get into it. How do we overload operators in Kotlin?

Let’s use the choir class from the initial example; we will need to overload the += operator to add a singer.

You can use the operator like this:

Voila! The overloaded operator makes the code a lot more readable and concise.

What other operators would you want to overload?

It probably won’t make sense to overload all of the operators for a custom type, but usually you’ll want more than one. Overuse can hurt readability, so take some time to think about your type and what overloads will boost your code.

We overloaded the += operator to add someone to the choir but we also may want to see if a certain person is already a member of the choir. To do that, let’s overload the contains operator so we can use the in keyword.

Operator overloading in extensions

You can also use operator overloading with extension functions. In this example we overload the += operator for ViewGroup:

operator fun ViewGroup.plusAssign(other: View) = addView(other)

Now adding a view to a viewGroup is super simple!!

viewGroup += view

Best practices from other languages

Operator overloading is also used in many other languages including C++, Python, Swift, and PHP. While we don’t have any clear best practices in Kotlin for now, there are some that we can learn from these other languages:

  • Conciseness does not always equal more readable code. Think about if your code will actually be more readable if operator overloading is added.
  • If the result of your overload does not make sense within the context of the language or is unclear in any way, you should use a function instead. For example if you add two books, it is not immediately clear what the end product would be. Would it be a new book? How would they be combined? If you have to ask, then you should use a function instead.
  • If one operator is overloaded, think through the other operators one may expect to be overloaded as well. For example if you overload -, you would also want to overload -=. In our choir example, because we were able to add a singer using +=, we should also be able to remove a singer using -=.

What is under the hood?

Operator overloading is implemented under the hood by rewriting the operator with a standard function call. For example, the code to add a choir member is:

If we look at the decompiled Java code, we can see how this works:

The compiler simply replaced the += with a normal member function call.

Conclusion

Operator overloading must be used carefully; but when you do, it is a powerful tool to make your code more expressive and concise.

  • Make sure you use the operator keyword or else Kotlin will treat your function as a normal function and your code will not compile.
  • Check if overloading operators will actually make your code more readable.
  • Think through which operators make sense to overload for your types.

Join in my choir of singing the praises of operator overloading!

Bonus photo of me singing at a choir showcase!

--

--