Kotlin operator Keyword
last modified April 19, 2025
Kotlin's operator overloading allows you to define custom behavior for standard
operators. The operator
keyword marks functions that overload
operators. This tutorial explores operator overloading in depth with examples.
Basic Definitions
The operator
keyword in Kotlin is used to declare functions that
overload operators. Each operator has a predefined function name that must be
used. Operator overloading makes code more readable and intuitive for domain-
specific operations.
Overloading the Plus Operator
The plus
operator function overloads the +
operator.
You can define custom addition behavior for your classes. The function must be
marked with the operator
keyword.
package com.zetcode data class Point(val x: Int, val y: Int) { operator fun plus(other: Point): Point { return Point(x + other.x, y + other.y) } } fun main() { val p1 = Point(1, 2) val p2 = Point(3, 4) val p3 = p1 + p2 println(p3) // Output: Point(x=4, y=6) }
Here we define a plus
operator for the Point class. It adds the x
and y coordinates of two points. The +
operator now works with Point
objects, making the code more intuitive.
Overloading the Comparison Operators
Comparison operators like <
and >
can be
overloaded using the compareTo
function. This function should return
a negative, zero, or positive integer.
package com.zetcode data class Person(val name: String, val age: Int) { operator fun compareTo(other: Person): Int { return age.compareTo(other.age) } } fun main() { val alice = Person("Alice", 30) val bob = Person("Bob", 25) println(alice > bob) // Output: true println(alice < bob) // Output: false }
The compareTo
operator compares Person objects by age. This enables
using standard comparison operators with custom objects. The function returns the
result of comparing the ages.
Overloading the Index Access Operator
The get
and set
operators overload the index access
operators []
. This allows your class to behave like an array or
collection.
package com.zetcode class StringCollection(private val strings: List) { operator fun get(index: Int): String { return strings[index] } operator fun set(index: Int, value: String) { // Strings are immutable in List, so this is just for demo println("Setting index $index to $value") } } fun main() { val collection = StringCollection(listOf("a", "b", "c")) println(collection[1]) // Output: b collection[1] = "x" // Output: Setting index 1 to x }
Here we define index access for a StringCollection class. The get
operator retrieves values, while set
allows modification. Note that
the underlying List is immutable in this example.
Overloading the Invoke Operator
The invoke
operator allows an object to be called like a function.
This can make DSLs or builder patterns more concise and readable.
package com.zetcode class Greeter(private val greeting: String) { operator fun invoke(name: String) { println("$greeting, $name!") } } fun main() { val hello = Greeter("Hello") hello("John") // Output: Hello, John! val hi = Greeter("Hi") hi("Sarah") // Output: Hi, Sarah! }
The Greeter class defines an invoke
operator that takes a name and
prints a greeting. This allows Greeter instances to be called like functions,
making the syntax more natural for this use case.
Overloading Unary Operators
Unary operators like +
, -
, and !
can be
overloaded using specific function names. These operators work on a single
operand.
package com.zetcode data class Counter(var value: Int) { operator fun inc(): Counter { return Counter(value + 1) } operator fun dec(): Counter { return Counter(value - 1) } operator fun unaryMinus(): Counter { return Counter(-value) } } fun main() { var counter = Counter(5) println(++counter) // Output: Counter(value=6) println(--counter) // Output: Counter(value=5) println(-counter) // Output: Counter(value=-5) }
The Counter class overloads increment (inc
), decrement
(dec
), and unary minus (unaryMinus
) operators. These
enable using ++
, --
, and -
with Counter
objects.
Overloading Compound Assignment Operators
Compound assignment operators like +=
can be overloaded using the
plusAssign
function. These operators modify the left operand.
package com.zetcode class ShoppingCart { private val items = mutableListOf() operator fun plusAssign(item: String) { items.add(item) } fun showItems() { println("Cart contains: $items") } } fun main() { val cart = ShoppingCart() cart += "Apple" cart += "Banana" cart.showItems() // Output: Cart contains: [Apple, Banana] }
The ShoppingCart class overloads the +=
operator using
plusAssign
. This allows adding items to the cart with a concise
syntax. The operator modifies the cart's internal state.
Overloading the Range Operator
The rangeTo
operator overloads the ..
operator to
create ranges. This is useful for creating domain-specific range expressions.
package com.zetcode data class Date(val year: Int, val month: Int, val day: Int) { operator fun rangeTo(other: Date): List{ val dates = mutableListOf () var current = this while (current <= other) { dates.add(current) current = current.nextDay() } return dates } private fun nextDay(): Date { // Simplified implementation return if (day < 28) copy(day = day + 1) else if (month < 12) copy(month = month + 1, day = 1) else copy(year = year + 1, month = 1, day = 1) } operator fun compareTo(other: Date): Int { return when { year != other.year -> year - other.year month != other.month -> month - other.month else -> day - other.day } } } fun main() { val start = Date(2023, 1, 1) val end = Date(2023, 1, 3) val range = start..end println(range) // Output: [Date(year=2023, month=1, day=1), ...] }
This example shows how to create a date range using the ..
operator.
The rangeTo
operator generates all dates between two dates. The
compareTo
operator is also needed for range comparisons.
Best Practices for Operator Overloading
- Maintain intuitive behavior: Operators should behave in ways that users would expect from similar built-in types.
- Don't overload excessively: Only overload operators when it makes the code more readable and the operation is fundamental to the type.
- Follow mathematical conventions: For mathematical operations, follow standard mathematical rules and properties.
- Document overloaded operators: Clearly document the behavior of overloaded operators in your class documentation.
- Consider performance: Operator functions might be called frequently, so ensure they're efficient.
Source
Kotlin Operator Overloading Documentation
This tutorial covered Kotlin's operator
keyword in depth, showing
how to overload various operators for custom types. We explored arithmetic,
comparison, indexing, and other operator types. Proper use of operator
overloading can make domain-specific code more expressive and readable.
Author
List all Kotlin tutorials.