Kotlin Operator Overloading
Operator overloading lets you define what standard operators like +, -, *, ==, and [] do when applied to your own classes. Your custom types then feel as natural to use as built-in types.
The operator Keyword
data class Vector(val x: Double, val y: Double) {
operator fun plus(other: Vector) = Vector(x + other.x, y + other.y)
operator fun minus(other: Vector) = Vector(x - other.x, y - other.y)
operator fun times(scale: Double) = Vector(x * scale, y * scale)
operator fun unaryMinus() = Vector(-x, -y)
override fun toString() = "Vector(${"%.2f".format(x)}, ${"%.2f".format(y)})"
}
fun main() {
val v1 = Vector(3.0, 4.0)
val v2 = Vector(1.0, 2.0)
println(v1 + v2) // Vector(4.00, 6.00)
println(v1 - v2) // Vector(2.00, 2.00)
println(v1 * 2.0) // Vector(6.00, 8.00)
println(-v1) // Vector(-3.00, -4.00)
}Operator to Function Mapping
Operator │ Function Name │ Example
──────────┼─────────────────┼────────────────────
+ │ plus │ a + b
- │ minus │ a - b
* │ times │ a * b
/ │ div │ a / b
% │ rem │ a % b
-x │ unaryMinus │ -a
++ │ inc │ a++
-- │ dec │ a--
[] │ get │ a[i]
[]= │ set │ a[i] = v
in │ contains │ x in a
== │ equals │ a == b (from data class)
<, > │ compareTo │ a < b
Index Operator
class Matrix(private val data: Array) {
operator fun get(row: Int, col: Int): Int = data[row][col]
operator fun set(row: Int, col: Int, value: Int) { data[row][col] = value }
}
fun main() {
val m = Matrix(arrayOf(intArrayOf(1,2,3), intArrayOf(4,5,6), intArrayOf(7,8,9)))
println(m[1, 2]) // 6 (row 1, col 2)
m[0, 0] = 99
println(m[0, 0]) // 99
} Comparison Operator
data class Version(val major: Int, val minor: Int, val patch: Int) : Comparable {
override fun compareTo(other: Version): Int {
if (major != other.major) return major.compareTo(other.major)
if (minor != other.minor) return minor.compareTo(other.minor)
return patch.compareTo(other.patch)
}
override fun toString() = "$major.$minor.$patch"
}
fun main() {
val v1 = Version(2, 0, 0)
val v2 = Version(1, 9, 5)
val v3 = Version(2, 0, 1)
println(v1 > v2) // true
println(v1 < v3) // true
val versions = listOf(v3, v1, v2)
println(versions.sorted()) // [1.9.5, 2.0.0, 2.0.1]
println("Latest: ${versions.max()}") // Latest: 2.0.1
} in Operator
class NumberRange(val start: Int, val end: Int) {
operator fun contains(value: Int) = value in start..end
}
fun main() {
val range = NumberRange(10, 50)
println(25 in range) // true
println(5 in range) // false
println(60 !in range) // true
}Practical Example: Money Class
data class Money(val amount: Double, val currency: String = "INR") {
operator fun plus(other: Money): Money {
require(currency == other.currency) { "Currency mismatch" }
return Money(amount + other.amount, currency)
}
operator fun minus(other: Money): Money {
require(currency == other.currency) { "Currency mismatch" }
return Money(amount - other.amount, currency)
}
operator fun times(factor: Double) = Money(amount * factor, currency)
operator fun compareTo(other: Money) = amount.compareTo(other.amount)
override fun toString() = "$currency ${"%.2f".format(amount)}"
}
fun main() {
val price = Money(1500.0)
val shipping = Money(100.0)
val discount = Money(200.0)
val total = price + shipping - discount
println("Total: $total") // INR 1400.00
val withTax = total * 1.18
println("With tax: $withTax") // INR 1652.00
println(price > discount) // true
}