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.
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
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
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()membuatv1 + v2diterjemahkan menjadiv1.plus(v2).rangeTo()membuat ekspresiv1..v2diterjemahkan menjadiv1.rangeTo(v2).
1. Unary Operator Overloading
Operator unary bekerja pada satu operan, seperti +a, -a, a++, a--. Setiap operator memiliki konvensi fungsi tertentu:
+a→unaryPlus()-a→unaryMinus()!a→not()a++→inc()a--→dec()
Contoh
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
| Operator | Fungsi |
|---|---|
++a | inc() |
--a | dec() |
-a | unaryMinus() |
+a | unaryPlus() |
!a | not() |
2. Binary Operator Overloading
Operator binary melibatkan dua operan. Kotlin memiliki konvensi berikut:
a + b→a.plus(b)a - b→a.minus(b)a * b→a.times(b)a / b→a.div(b)a % b→a.rem(b)
Operator assignment:
a += b→plusAssign(b)a -= b→minusAssign(b)
Contoh
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
| Operator | Fungsi |
|---|---|
a + b | plus(b) |
a - b | minus(b) |
a * b | times(b) |
a / b | div(b) |
a % b | rem(b) |
a += b | plusAssign(b) |
a -= b | minusAssign(b) |
a *= b | timesAssign(b) |
a /= b | divAssign(b) |
a %= b | remAssign(b) |
a == b | equals(b) |
a > b | compareTo(b) |
a < b | compareTo(b) |
a >= b | compareTo(b) |
a <= b | compareTo(b) |
3. Indexing Operator
Kotlin menerjemahkan:
a[i]menjadia.get(i)a[i, j]menjadia.get(i, j)a[i] = xmenjadia.set(i, x)
Contoh
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
| Operator | Fungsi |
|---|---|
a[i] | get(i) |
a[i, j] | get(i, j) |
a[i] = b | set(i, b) |
a[i, j] = b | set(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
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 bmenjadib.contains(a)a !in bmenjadi!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
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
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 = ""storedberfungsi sebagai tempat penyimpanan sebenarnya.- Data properti
namepadaGameCharactertidak 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. thisRefadalah objek pemilik properti (GameCharacter).propertyberisi 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
nametidak disimpan diGameCharacter. - 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
AliceFunctional Programming
Functional Programming (FP) adalah paradigma pemrograman yang menekankan penggunaan fungsi-fungsi murni, imutabilitas data, dan penghindaran perubahan status (state) secara langsung.
Complexity
Ukuran seberapa sulit suatu program atau sistem perangkat lunak untuk dipahami, dipelihara, dan dimodifikasi, dipengaruhi.