Operator overloading memungkinkan kita mendefinisikan perilaku +, -, *, [], in, dan operator lain pada class buatan sendiri. Kotlin menerapkan aturan ketat: hanya operator dengan nama function tertentu (plus, minus, times, dst.) yang dapat dipanggil lewat simbol. Setiap function harus ditandai dengan modifier operator. Pada chapter ini kita akan membangun class Vec yang mendukung +, -, *, [], dan in, lalu mengulas daftar operator yang dapat di-overload.
Daftar Operator yang Dapat Di-overload #
Berikut ringkasan operator utama beserta function konvensinya:
| Simbol | Function | Contoh deklarasi | Pemakaian |
|---|---|---|---|
+ | plus() | operator fun plus(o: T): T | a + b |
- | minus() | operator fun minus(o: T): T | a - b |
* | times() | operator fun times(n: Int): T | a * 2 |
/ | div() | operator fun div(n: Int): T | a / 2 |
% | rem() | operator fun rem(n: Int): T | a % 2 |
<, >, <=, >= | compareTo() | operator fun compareTo(o: T): Int | a < b |
[] (baca) | get() | operator fun get(i: Int): E | a[0] |
[] (tulis) | set() | operator fun set(i: Int, v: E) | a[0] = v |
in | contains() | operator fun contains(e: E): Boolean | x in a |
.. | rangeTo() | operator fun rangeTo(o: T): R | a..b |
() | invoke() | operator fun invoke(arg: A): R | a(arg) |
+= | plusAssign() | operator fun plusAssign(e: E) | a += b |
Modifier operator wajib ada. Tanpa modifier, function tetap dapat dipanggil secara normal sebagai a.plus(b), tetapi tidak dapat dipanggil lewat simbol a + b.
Mendefinisikan Operator pada Vec #
Berikut class Vec dua dimensi yang mendukung penjumlahan, pengurangan, perkalian skalar, indeks berbasis sumbu, dan pemeriksaan keanggotaan titik:
data class Vec(val x: Int, val y: Int) {
operator fun plus(other: Vec): Vec = Vec(x + other.x, y + other.y)
operator fun minus(other: Vec): Vec = Vec(x - other.x, y - other.y)
operator fun times(scalar: Int): Vec = Vec(x * scalar, y * scalar)
operator fun get(axis: Char): Int = when (axis) {
'x' -> x
'y' -> y
else -> 0
}
operator fun contains(point: Vec): Boolean = point.x in 0..x && point.y in 0..y
override fun toString(): String = "Vec($x, $y)"
}
fun main() {
val a = Vec(3, 4)
val b = Vec(1, 2)
println("a = $a")
println("b = $b")
println("a + b = ${a + b}")
println("a - b = ${a - b}")
println("a * 2 = ${a * 2}")
println("a['x'] = ${a['x']}")
println("a['y'] = ${a['y']}")
val pojok = Vec(2, 2)
println("Vec(2,2) in a: ${pojok in a}")
println("Vec(5,5) in a: ${Vec(5, 5) in a}")
val daftar = listOf(a, b, Vec(0, 0))
println("Daftar: $daftar")
val total = daftar.fold(Vec(0, 0)) { acc, v -> acc + v }
println("Total fold: $total")
}Output yang Dihasilkan:
a = Vec(3, 4)
b = Vec(1, 2)
a + b = Vec(4, 6)
a - b = Vec(2, 2)
a * 2 = Vec(6, 8)
a['x'] = 3
a['y'] = 4
Vec(2,2) in a: true
Vec(5,5) in a: false
Daftar: [Vec(3, 4), Vec(1, 2), Vec(0, 0)]
Total fold: Vec(4, 6)Mari kita bedah setiap bagian pada contoh di atas:
operator fun plus(other: Vec): Vecmendefinisikan perilakua + b. Function mengembalikanVecbaru dengan komponen yang dijumlahkan. Modifieroperatorwajib; tanpa modifier, simbol+tidak akan dikenali.operator fun times(scalar: Int): Vecmendefinisikan perkalian dengan skalar. Tipe operand kedua berbeda (Int), namun Kotlin mengizinkan tipe operand berbeda pada operator yang di-overload. Tidak ada operator otomatis2 * a(operand pertamaInt); bila diperlukan, definisikan extension functionoperator fun Int.times(v: Vec): Vec.operator fun get(axis: Char): Intmendefinisikan akses indeksa['x']. Parameter tidak harusInt— kita memakaiCharsebagai sumbu. Fleksibilitas ini memungkinkan API yang ekspresif sepertimatrix['x', 'y'].operator fun contains(point: Vec): Booleanmendefinisikan operatorin. Pemeriksaanpojok in asekarang berarti apakah pojok berada dalam kotak dari origin kea. Tidak ada hubungan dengan pemeriksaan kesetaraan nilai; semantikinditentukan sepenuhnya oleh implementasi function.daftar.fold(Vec(0, 0)) { acc, v -> acc + v }menjumlahkan semuaVecdalam list menggunakan operator+yang sudah di-overload. Lambda di dalamfoldmenggunakanacc + v, yang dipetakan ke pemanggilanacc.plus(v). Tanpa operator overloading, kode ini akan menjadiacc.plus(v)yang lebih bertele-tele.
Aturan Penting Operator Overloading #
Kotlin menerapkan beberapa aturan untuk menjaga keterbacaan dan keamanan:
| Aturan | Penjelasan |
|---|---|
Modifier operator wajib | Mencegah function biasa tak sengaja dipanggil lewat simbol |
| Nama function harus tepat | plus() untuk +, bukan add() atau nama lain |
| Tidak boleh membuat operator baru | Kita tidak dapat menambahkan %% atau ^^; hanya simbol yang sudah dikenal |
| Precedence tetap mengikuti standar | Operator * selalu lebih tinggi dari + walau di-overload |
| Asosiativitas tetap | Operator binary tetap left-associative kecuali .. dan assignment |
Operator get, set, dan invoke #
Operator get dan set memungkinkan class kita berperilaku seperti array atau map. Operator invoke memungkinkan instance class dipanggil seperti function. Kombinasi ketiga operator ini sering dipakai untuk membangun DSL yang ekspresif:
class Validator {
operator fun invoke(input: String): Boolean =
input.length in 1..100
}
val validator = Validator()
val ok = validator("data valid") // trueOperator invoke juga bekerja dengan multi-parameter. Class yang mengimplementasikan operator fun invoke(a: A, b: B): R dapat dipanggil sebagai instance(a, b), seolah-olah instance adalah function.
Referensi Lanjutan #
- Operator overloading — panduan resmi konvensi operator overloading di Kotlin
Dengan menguasai operator overloading, kita dapat membangun API yang terbaca seperti aritmetika atau akses map. Selanjutnya, kita perlu memahami urutan precedence dan asosiativitas agar ekspresi yang menggunakan banyak operator dapat dievaluasi sesuai harapan.