kotlinintermediate

Kotlin Operator Overloading

Overload operators for custom types: arithmetic, comparison, indexing, destructuring, and invoke.

kotlin
// Vector2D with operator overloading
data class Vector2D(val x: Double, val y: Double) {
    // Arithmetic operators
    operator fun plus(other: Vector2D) = Vector2D(x + other.x, y + other.y)
    operator fun minus(other: Vector2D) = Vector2D(x - other.x, y - other.y)
    operator fun times(scalar: Double) = Vector2D(x * scalar, y * scalar)
    operator fun div(scalar: Double) = Vector2D(x / scalar, y / scalar)
    operator fun unaryMinus() = Vector2D(-x, -y)

    // Comparison
    operator fun compareTo(other: Vector2D): Int =
        magnitude().compareTo(other.magnitude())

    fun magnitude() = Math.sqrt(x * x + y * y)

    // Destructuring (already provided by data class)
    // operator fun component1() = x
    // operator fun component2() = y

    override fun toString() = "($x, $y)"
}

// Extension operator
operator fun Double.times(v: Vector2D) = v * this

// Matrix with index operator
class Matrix(val rows: Int, val cols: Int) {
    private val data = Array(rows) { DoubleArray(cols) }

    operator fun get(row: Int, col: Int): Double = data[row][col]
    operator fun set(row: Int, col: Int, value: Double) { data[row][col] = value }

    operator fun plus(other: Matrix): Matrix {
        require(rows == other.rows && cols == other.cols)
        return Matrix(rows, cols).also { result ->
            for (r in 0 until rows)
                for (c in 0 until cols)
                    result[r, c] = this[r, c] + other[r, c]
        }
    }

    override fun toString(): String =
        data.joinToString("\n") { row -> row.joinToString(", ") { "%.1f".format(it) } }
}

// Invoke operator
class Validator<T>(private val rules: List<(T) -> String?>) {
    operator fun invoke(value: T): List<String> =
        rules.mapNotNull { it(value) }
}

// contains operator for range-like check
data class DateRange(val start: Int, val end: Int) {
    operator fun contains(day: Int) = day in start..end
}

fun main() {
    // Vector operations
    val v1 = Vector2D(3.0, 4.0)
    val v2 = Vector2D(1.0, 2.0)
    println("v1 + v2 = ${v1 + v2}")
    println("v1 - v2 = ${v1 - v2}")
    println("v1 * 2 = ${v1 * 2.0}")
    println("2 * v1 = ${2.0 * v1}")
    println("-v1 = ${-v1}")

    // Destructuring
    val (x, y) = v1
    println("x=$x, y=$y")

    // Matrix
    val m = Matrix(2, 2)
    m[0, 0] = 1.0; m[0, 1] = 2.0
    m[1, 0] = 3.0; m[1, 1] = 4.0
    println("Matrix:\n$m")

    // Invoke
    val validateAge = Validator<Int>(listOf(
        { if (it < 0) "Must be positive" else null },
        { if (it > 150) "Unrealistic age" else null }
    ))
    println("Validate 25: ${validateAge(25)}")
    println("Validate -5: ${validateAge(-5)}")

    // contains
    val vacation = DateRange(15, 25)
    println("20 in vacation: ${20 in vacation}")
    println("10 in vacation: ${10 in vacation}")
}

Use Cases

  • Mathematical libraries with natural syntax
  • Domain-specific types with operations
  • Indexable and callable objects

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.