Kotlin

Convention & Operator Overloading

Operator Overloading memungkinkan kita memberikan implementasi khusus pada operator bawaan untuk kelas tertentu. Konvensi (conventions) adalah aturan penamaan fungsi khusus yang digunakan compiler untuk menghubungkan operator dengan fungsi tersebut.

Author : Celvine Adi Putra | Date : November 28, 2025

Operator Overloading

Operator overloading adalah kemampuan memberikan perilaku khusus pada operator (seperti +, -, *) untuk tipe data buatan. Di Kotlin, hal ini dilakukan dengan membuat fungsi khusus yang diberi modifier operator. Compiler kemudian menerjemahkan penggunaan operator menjadi pemanggilan fungsi tersebut.

Sebagai contoh, fungsi operator fun plus() akan membuat ekspresi a + b diterjemahkan menjadi a.plus(b).

Contoh

contoh1.kt
data class Vector(val x: Int, val y: Int) {
    operator fun plus(other: Vector): Vector {
        return Vector(x + other.x, y + other.y)
    }
    operator fun minus(other: Vector): Vector {
        return Vector(x - other.x, y - other.y)
    }
}

fun main() {
    val v1 = Vector(2, 3)
    val v2 = Vector(4, 1)
    println(v1 + v2)
    println(v1 - v2)
}

Penjelasan

Dengan menandai fungsi plus dan minus menggunakan modifier operator, Kotlin menghubungkan operator + dan - ke fungsi yang sesuai. Ini membuat operasi pada objek.

Conventions

Konvensi adalah aturan penamaan fungsi khusus yang dikenali compiler. Jika fungsi mengikuti nama konvensi dan diberi modifier operator, maka operator yang sesuai dapat digunakan. Contoh: plus() untuk +, minus() untuk -, get() untuk [ ], contains() untuk in, dan seterusnya.

Contoh

contoh2.kt
data class Vector(val x: Int, val y: Int) {
    operator fun plus(other: Vector): Vector = Vector(x + other.x)
    operator fun rangeTo(other: Vector): Pair<Vector, Vector> = Pair(this, other)
}

Penjelasan

  • plus() membuat v1 + v2 diterjemahkan menjadi v1.plus(v2).
  • rangeTo() membuat ekspresi v1..v2 diterjemahkan menjadi v1.rangeTo(v2).

1. Unary Operator Overloading

Operator unary bekerja pada satu operan, seperti +a, -a, a++, a--. Setiap operator memiliki konvensi fungsi tertentu:

  • +aunaryPlus()
  • -aunaryMinus()
  • !anot()
  • a++inc()
  • a--dec()

Contoh

contoh2.kt
data class Vector(var x: Int, var y: Int) {
    operator fun unaryMinus(): Vector = Vector(-x, -y)
    operator fun inc(): Vector = Vector(x + 1, y + 1)
    operator fun dec(): Vector = Vector(x - 1, y - 1)
}

fun main() {
    var v = Vector(2, 3)
    println(-v)
    println(v++)
    println(++v)
}

Penjelasan Kode

unaryMinus() membalik nilai komponen. inc() dan dec() menghasilkan objek baru dan digunakan untuk operasi prefix maupun postfix.

Tabel Unary Operator

OperatorFungsi
++ainc()
--adec()
-aunaryMinus()
+aunaryPlus()
!anot()

2. Binary Operator Overloading

Operator binary melibatkan dua operan. Kotlin memiliki konvensi berikut:

  • a + ba.plus(b)
  • a - ba.minus(b)
  • a * ba.times(b)
  • a / ba.div(b)
  • a % ba.rem(b)

Operator assignment:

  • a += bplusAssign(b)
  • a -= bminusAssign(b)

Contoh

contoh3.kt
data class Vector(var x: Int, var y: Int) {
    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 plusAssign(other: Vector) {
        x += other.x
        y += other.y
    }
}

fun main() {
    var v = Vector(1, 2)
    val u = Vector(3, 4)
    println(v + u)
    v += u
    println(v)
}

Penjelasan Kode

plus() dan minus() mengembalikan objek baru. plusAssign() melakukan mutasi nilai pada objek.

Tabel Operator Binary

OperatorFungsi
a + bplus(b)
a - bminus(b)
a * btimes(b)
a / bdiv(b)
a % brem(b)
a += bplusAssign(b)
a -= bminusAssign(b)
a *= btimesAssign(b)
a /= bdivAssign(b)
a %= bremAssign(b)
a == bequals(b)
a > bcompareTo(b)
a < bcompareTo(b)
a >= bcompareTo(b)
a <= bcompareTo(b)

3. Indexing Operator

Kotlin menerjemahkan:

  • a[i] menjadi a.get(i)
  • a[i, j] menjadi a.get(i, j)
  • a[i] = x menjadi a.set(i, x)

Contoh

contoh3.kt
class Matrix(private val rows: Int, private val cols: Int) {
    private val data = Array(rows) { IntArray(cols) }

    operator fun get(i: Int, j: Int): Int = data[i][j]
    operator fun set(i: Int, j: Int, value: Int) {
        data[i][j] = value
    }
}

fun main() {
    val m = Matrix(3, 3)
    m[0, 0] = 1
    m[1, 2] = 5
    println(m[0, 0])
    println(m[1, 2])
}

Tabel Indexing Operator

OperatorFungsi
a[i]get(i)
a[i, j]get(i, j)
a[i] = bset(i, b)
a[i, j] = bset(i, j, b)
a()invoke()
a(i)invoke(i)
a(i, j)invoke(i, j)

4. Operator in dan !in

a in b diterjemahkan menjadi b.contains(a). a !in b diterjemahkan menjadi !b.contains(a).

Contoh

contoh3.kt
class GameCharacter(val inventory: List<String>) {
    operator fun contains(item: String): Boolean {
        return inventory.contains(item)
    }
}

fun main() {
    val hero = GameCharacter(listOf("Sword", "Shield", "Potion"))
    println("Potion" in hero)
    println("Bow" !in hero)
}

Penjelasan

Operator in dan !in digunakan untuk memeriksa apakah sebuah nilai terdapat di dalam suatu objek. Kotlin menerjemahkan:

  • a in b menjadi b.contains(a)
  • a !in b menjadi !b.contains(a)

Pada contoh di atas, kelas GameCharacter memiliki daftar inventory. Dengan menambahkan fungsi operator fun contains(item: String), kita memberi tahu Kotlin bagaimana mengecek apakah suatu item ada di dalam objek GameCharacter.

Ketika kode "Potion" in hero dijalankan, Kotlin memanggil hero.contains("Potion"), lalu mengembalikan true karena "Potion" memang berada di dalam list inventaris. Sebaliknya, "Bow" !in hero berarti !hero.contains("Bow"), menghasilkan true karena "Bow" tidak ada di dalam inventaris.

Dengan ini, pengecekan keanggotaan dapat ditulis lebih alami dan ekspresif menggunakan syntax in dan !in.


5. Operator Range (..)

a..b diterjemahkan menjadi a.rangeTo(b). Untuk tipe buatan, kita dapat membuat operator fun rangeTo.

Contoh

contoh3.kt
data class GameLevel(val number: Int) : Comparable<GameLevel> {
    override fun compareTo(other: GameLevel) = number - other.number
    operator fun rangeTo(other: GameLevel) = number..other.number
}

fun main() {
    val level1 = GameLevel(1)
    val level3 = GameLevel(3)
    val rangeLevel = level1..level3
    println(rangeLevel)
}

Penjelasan

Operator range (..) digunakan untuk membuat rentang nilai dari objek kiri hingga objek kanan. Kotlin menerjemahkan ekspresi a..b menjadi pemanggilan a.rangeTo(b).

Pada contoh di atas, kelas GameLevel mengimplementasikan Comparable agar dua level dapat dibandingkan. Fungsi operator fun rangeTo(other: GameLevel) mengembalikan IntRange dari nilai level saat ini (number) hingga level tujuan.

Ketika kode level1..level3 dijalankan, Kotlin memanggil:

level1.rangeTo(level3)

Hasilnya adalah rentang 1..3. Sehingga, tipe GameLevel dapat menggunakan operator .. secara alami untuk membentuk range berdasarkan nilai level.


6. Konvensi Properti Delegasi

Delegated properties memakai kata kunci by. Kelas delegate harus menyediakan getValue dan setValue (untuk var).

Contoh

contoh3.kt
import kotlin.reflect.KProperty

class StorageDelegate {
    private var stored: String = ""

    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return stored
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("Menyimpan \"$value\" ke properti ${property.name}")
        stored = value
    }
}

class GameCharacter {
    var name: String by StorageDelegate()
}

fun main() {
    val hero = GameCharacter()
    hero.name = "Alice"
    println(hero.name)
}

Penjelasan

1. StorageDelegate sebagai Delegate

class StorageDelegate {
    private var stored: String = ""
  • stored berfungsi sebagai tempat penyimpanan sebenarnya.
  • Data properti name pada GameCharacter tidak disimpan di kelas itu sendiri, tetapi di sini.

2. getValue — Mengambil nilai

operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
    return stored
}
  • Dipanggil ketika kode menjalankan hero.name.
  • thisRef adalah objek pemilik properti (GameCharacter).
  • property berisi metadata properti (nama, tipe, dll).
  • Mengembalikan nilai yang disimpan dalam stored.

3. setValue — Menetapkan nilai

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
    println("Menyimpan \"$value\" ke properti ${property.name}")
    stored = value
}
  • Dipanggil saat hero.name = "Alice".
  • Menampilkan pesan logging setiap kali properti ditulis.
  • Menyimpan nilai baru ke variabel stored.

4. Penggunaan pada GameCharacter

class GameCharacter {
    var name: String by StorageDelegate()
}
  • Properti name tidak disimpan di GameCharacter.
  • Semua logika get/set dialihkan ke objek StorageDelegate.

5. Alur Eksekusi main()

val hero = GameCharacter()
hero.name = "Alice"   // memicu setValue(...)
println(hero.name)     // memicu getValue(...)

Output:

Menyimpan "Alice" ke properti name
Alice
Convention & Operator Overloading