Masukkan Password
36 The Complete Kotlin Course #35- Function As Variable - Kotlin Tutorials for Beginners
Lesson ini memang terasa lebih membingungkan dibanding lesson sebelumnya, karena sekarang kita masuk ke konsep bahwa function juga bisa diperlakukan sebagai sebuah value.
Tapi sebenarnya idenya sederhana kalau kita pecah pelan-pelan.
Sebelumnya kamu belajar:
function
→ punya parameter
→ bisa mengembalikan value
Sekarang naik satu tingkat:
function
→ juga bisa disimpan ke variable
→ bisa dikirim sebagai argument ke function lain
Konsep ini menjadi salah satu fondasi penting untuk higher-order function, lambda, map, filter, dan banyak fitur Kotlin lainnya.
1. Ide Utama Lesson Ini
Instruktur mengatakan:
Functions in Kotlin are simply another data type.
Untuk pemahaman awal, ini boleh kita jadikan mental model:
Function dapat diperlakukan sebagai sebuah value yang bisa direferensikan, disimpan, dan dikirim ke function lain.
Misalnya sebelumnya kita punya value biasa:
val number = 10
number menyimpan angka.
Kita juga bisa punya:
val name = "Andi"
name menyimpan String.
Sekarang kita bisa membuat variable yang menyimpan referensi ke sebuah function.
Contohnya:
fun add(x: Int, y: Int): Int {
return x + y
}
Kemudian function tersebut direferensikan oleh:
val t = ::add
Sekarang t merujuk ke function add.
2. Mulai dari Function add
Function dari video kira-kira:
fun add(x: Int, y: Int): Int {
return x + y
}
Artinya:
Nama function = add
Parameter 1 = x : Int
Parameter 2 = y : Int
Return type = Int
Kalau kita panggil secara biasa:
add(4, 5)
hasilnya:
9
Karena:
4 + 5 = 9
Sampai di sini seharusnya sudah familiar karena ini gabungan materi sebelumnya:
parameter
+
return
3. Sekarang Ada Sesuatu yang Baru
Biasanya kita langsung memanggil:
add(4, 5)
Tetapi Kotlin memungkinkan kita membuat referensi terhadap function:
::add
Perhatikan simbolnya:
::
Ini disebut callable reference operator, dan untuk function top-level seperti contoh ini kita dapat menggunakannya sebagai function reference.
Jadi:
::add
artinya kira-kira:
“Referensi ke function
add.”
4. Sangat Penting: add vs ::add vs add(...)
Ini bagian yang sering membingungkan.
Kita punya tiga hal berbeda:
1. Function declaration
fun add(x: Int, y: Int): Int {
return x + y
}
Kita membuat function.
2. Function call
add(4, 5)
Kita menjalankan function.
3. Function reference
::add
Kita mengambil referensi ke function.
Jadi:
add(4, 5)
→ jalankan function
::add
→ ambil referensi ke function
Ini perbedaan yang sangat penting.
5. Function Reference Bisa Disimpan di Variable
Contoh:
fun add(x: Int, y: Int): Int {
return x + y
}
val t = ::add
Sekarang:
t
bukan angka 9.
t adalah variable yang menyimpan referensi ke function add.
Kita bisa membayangkannya:
add
│
│ reference
↓
t
Atau:
t ─────────→ add()
6. Type dari Variable t
Nah, bagian inilah yang membuat lesson ini terasa aneh pada awalnya.
Kalau:
val number = 10
type-nya:
Int
Kalau:
val name = "Andi"
type-nya:
String
Tetapi:
val t = ::add
type-nya adalah function type.
Karena add menerima:
Int
Int
dan menghasilkan:
Int
maka function type-nya adalah:
(Int, Int) -> Int
Ini dibaca:
Function yang menerima dua
Intdan menghasilkan satuInt.
7. Memahami (Int, Int) -> Int
Jangan takut dengan bentuk ini.
Pisahkan menjadi:
(Int, Int) → Int
Bagian kiri:
(Int, Int)
berarti function menerima dua parameter, keduanya Int.
Bagian kanan:
Int
berarti function menghasilkan Int.
Jadi:
(Int, Int) -> Int
=
input:
Int
Int
output:
Int
Contoh function yang cocok:
fun add(x: Int, y: Int): Int {
return x + y
}
8. Kita Bisa Menuliskan Type-nya Secara Eksplisit
Kita bisa menulis:
val t: (Int, Int) -> Int = ::add
Artinya:
tadalah variable yang menyimpan sebuah function yang menerima duaIntdan mengembalikanInt.
Tetapi Kotlin juga bisa melakukan type inference:
val t = ::add
Kotlin sendiri bisa mengetahui bahwa t bertipe:
(Int, Int) -> Int
Jadi ini:
val t = ::add
sudah cukup.
9. Function Variable Bisa Dipanggil
Nah, ini bagian yang paling menarik.
Kita tadi punya:
val t = ::add
Sekarang kita bisa:
t(5, 5)
Hasil:
10
Kenapa?
Karena t menunjuk ke function add.
Secara mental:
t
↓
add
↓
5 + 5
↓
10
Jadi:
t(5, 5)
pada dasarnya menjalankan function yang dirujuk oleh t.
10. Contoh Lengkap
fun add(x: Int, y: Int): Int {
return x + y
}
fun main() {
val t = ::add
val result = t(5, 5)
println(result)
}
Output:
10
Alurnya:
::add
↓
disimpan ke t
↓
t = function (Int, Int) -> Int
↓
t(5, 5)
↓
add(5, 5)
↓
10
↓
result = 10
11. Kenapa Tidak Langsung Pakai add(5, 5)?
Ini pertanyaan yang sangat bagus.
Kalau hanya ingin menghitung:
val result = add(5, 5)
jelas lebih sederhana.
Lalu kenapa harus:
val t = ::add
val result = t(5, 5)
?
Karena function reference berguna ketika function ingin diperlakukan sebagai data.
Misalnya kita ingin mengirim function ke function lain.
Nah, ini yang menjadi tujuan utama lesson ini.
12. Function Bisa Dikirim ke Function Lain
Misalnya kita punya:
fun printResult(
operation: (Int, Int) -> Int,
a: Int,
b: Int
) {
val result = operation(a, b)
println(result)
}
Perhatikan parameter pertama:
operation: (Int, Int) -> Int
Artinya:
function
printResultmenerima sebuah function sebagai parameter.
Jadi bukan hanya:
Int
String
Boolean
yang bisa menjadi parameter.
Kita juga bisa memberikan:
function
sebagai parameter.
13. Kita Kirim add ke printResult
Karena add memiliki type:
(Int, Int) -> Int
dan parameter operation membutuhkan:
(Int, Int) -> Int
maka cocok.
Kita bisa:
printResult(::add, 10, 20)
Alurnya:
::add
↓
masuk ke parameter operation
10
↓
parameter a
20
↓
parameter b
Kemudian di dalam function:
val result = operation(a, b)
karena:
operation → add
maka secara konsep itu menjadi:
val result = add(a, b)
Dengan:
a = 10
b = 20
hasil:
30
14. Program Lengkap
Contoh yang lebih rapi:
fun add(x: Int, y: Int): Int {
return x + y
}
fun printResult(
operation: (Int, Int) -> Int,
a: Int,
b: Int
) {
val result = operation(a, b)
println(result)
}
fun main() {
printResult(::add, 10, 20)
}
Output:
30
15. Mari Baca printResult() Pelan-Pelan
Deklarasinya:
fun printResult(
operation: (Int, Int) -> Int,
a: Int,
b: Int
)
Ada 3 parameter.
Parameter 1
operation: (Int, Int) -> Int
Ini bukan Int.
Ini adalah:
function yang menerima dua Int dan menghasilkan Int.
Parameter 2
a: Int
angka pertama.
Parameter 3
b: Int
angka kedua.
Jadi:
printResult(
sebuah function,
sebuah Int,
sebuah Int
)
16. Kemudian Function Memanggil Function
Di dalam:
val result = operation(a, b)
Ini sangat penting.
Sebelumnya kamu terbiasa:
add(a, b)
Sekarang:
operation(a, b)
Karena operation sendiri berisi referensi ke sebuah function.
Misalnya kita memanggil:
printResult(::add, 10, 20)
maka:
operation → add
a → 10
b → 20
sehingga:
operation(a, b)
menjadi secara konsep:
add(10, 20)
17. Inilah yang Disebut Higher-Order Function
Function yang:
menerima function sebagai parameter atau mengembalikan function sebagai result
disebut higher-order function.
Contoh:
fun printResult(
operation: (Int, Int) -> Int,
a: Int,
b: Int
) {
println(operation(a, b))
}
printResult adalah higher-order function karena menerima function:
operation: (Int, Int) -> Int
Ini adalah konsep yang sangat penting dalam Kotlin.
18. Kenapa Konsep Ini Berguna?
Sekarang bayangkan kita punya:
fun add(a: Int, b: Int): Int {
return a + b
}
fun multiply(a: Int, b: Int): Int {
return a * b
}
Keduanya memiliki function type yang sama:
(Int, Int) -> Int
Kita bisa membuat satu function:
fun calculate(
operation: (Int, Int) -> Int,
a: Int,
b: Int
): Int {
return operation(a, b)
}
Kemudian:
val addResult = calculate(::add, 10, 5)
val multiplyResult = calculate(::multiply, 10, 5)
Hasil:
addResult = 15
multiplyResult = 50
Perhatikan!
calculate() tidak perlu tahu apakah operation adalah:
add
atau:
multiply
Ia hanya tahu:
“Berikan saya sebuah function yang menerima dua Int dan menghasilkan Int.”
Ini adalah kekuatan besar dari function sebagai value.
19. Analogi Sederhana: Colokan
Bayangkan kita membuat mesin:
CALCULATOR
Mesin ini memiliki colokan untuk “operasi”:
operation
Kita bisa memasukkan:
ADD
atau:
MULTIPLY
atau nanti:
SUBTRACT
Mesinnya tetap sama.
calculate
↑
│
operation
├── add
├── multiply
└── subtract
Dalam Kotlin:
calculate(::add, 10, 5)
atau:
calculate(::multiply, 10, 5)
Function calculate tidak perlu dibuat berkali-kali.
20. Hubungkan dengan Variable Biasa
Kamu sebelumnya belajar:
val x = 10
Sekarang bayangkan function juga bisa menjadi sesuatu yang direferensikan:
val operation = ::add
Jadi secara mental:
x
↓
menunjuk ke angka
operation
↓
menunjuk ke function
Namun jangan terlalu mengartikan “function disimpan sebagai object persis seperti Int”. Untuk tahap awal, lebih aman menganggap kita menyimpan referensi/callable value yang dapat digunakan sebagai function.
21. Perbedaan ::add dan add
Ini wajib kamu kuasai.
add(5, 5)
Function langsung dipanggil.
jalankan add sekarang
::add
Mengambil referensi ke function.
berikan saya function add-nya
Contoh:
val result = add(5, 5)
langsung menghasilkan:
10
Sedangkan:
val operation = ::add
tidak menjalankan add.
Kita baru menjalankannya ketika:
operation(5, 5)
22. Ini Mirip dengan Menyimpan “Resep”
Bayangkan:
add
adalah resep membuat hasil penjumlahan.
::add seperti mengatakan:
“Berikan saya resepnya.”
Sedangkan:
add(5, 5)
seperti:
“Gunakan resepnya sekarang dengan bahan 5 dan 5.”
Jadi:
::add
→ referensi/resep
add(5, 5)
→ jalankan resep
23. Bisa Ada Banyak Function dengan Type yang Sama
Misalnya:
fun add(a: Int, b: Int): Int {
return a + b
}
fun multiply(a: Int, b: Int): Int {
return a * b
}
fun subtract(a: Int, b: Int): Int {
return a - b
}
Ketiganya memiliki type:
(Int, Int) -> Int
Karena semuanya:
menerima Int
menerima Int
menghasilkan Int
Artinya kita dapat membuat variable function seperti:
val operation: (Int, Int) -> Int = ::add
atau:
val operation: (Int, Int) -> Int = ::multiply
atau:
val operation: (Int, Int) -> Int = ::subtract
24. Variable Function Bisa Mengubah Referensi
Misalnya:
var operation: (Int, Int) -> Int = ::add
println(operation(5, 5))
hasil:
10
Kemudian:
operation = ::multiply
Lalu:
println(operation(5, 5))
hasil:
25
Karena sekarang:
operation → multiply
Ini menjelaskan kenapa function bisa dianggap sebagai value yang dapat dipindahkan/referensikan.
Namun untuk variable yang referensinya tidak akan berubah, lebih baik gunakan val:
val operation = ::add
25. Mengapa Instruktur Menggunakan var?
Di subtitle/video, instruktur membuat semacam variable function dengan var.
Padahal kalau kita tidak pernah mengubah referensinya, lebih baik:
val t = ::add
daripada:
var t = ::add
Karena val sudah cukup.
Kamu sebelumnya sudah belajar:
gunakan
valkalau tidak perlu reassignment.
Prinsip itu masih berlaku di sini.
26. Salah Kaprah Penting: Function Bukan “Return Type”
Di subtitle ada bagian yang terdengar seperti:
“t now is the returning type”
Ini kurang tepat.
t bukan “return type”.
t adalah variable yang memiliki function type.
Misalnya:
val t = ::add
maka:
t
↓
function value/reference
sedangkan:
(Int, Int) -> Int
adalah function type-nya.
Dan:
Int
yang terakhir adalah return type dari function tersebut.
Jadi:
(Int, Int) -> Int
│ │ │
│ │ └── return type
│ └───────── parameter type
└───────────────── parameter type
27. Function Type vs Return Type
Ini penting sekali.
Contoh:
fun add(x: Int, y: Int): Int
Return type:
Int
Tetapi function type-nya:
(Int, Int) -> Int
Jadi jangan tertukar.
return type
→ Int
function type
→ (Int, Int) -> Int
28. Kenapa Kita Bisa Print Function?
Subtitle mencoba melakukan:
println(t)
Tetapi ini bukan cara yang tepat untuk melihat hasil function.
t adalah referensi/function value, bukan hasil pemanggilan function.
Kalau kamu ingin hasil:
println(t(5, 5))
bukan:
println(t)
Perbedaannya:
t
→ function reference/value
t(5, 5)
→ menjalankan function dan menghasilkan Int
29. Hubungan dengan Expression
Kamu sudah belajar bahwa expression menghasilkan value.
Sekarang:
t(5, 5)
adalah sebuah function call yang menghasilkan value:
10
Karena itu bisa:
val result = t(5, 5)
atau:
println(t(5, 5))
atau:
val result = t(5, 5) + 10
30. Gambaran Besar Lesson Ini
Sekarang function bisa berada dalam beberapa peran.
1. Function biasa
fun add(a: Int, b: Int): Int {
return a + b
}
2. Function dipanggil
add(5, 5)
3. Function direferensikan
::add
4. Function reference disimpan
val operation = ::add
5. Function reference dipanggil
operation(5, 5)
6. Function reference dikirim ke function lain
printResult(::add, 5, 5)
Ini adalah inti seluruh lesson.
31. Diagram Lengkap
Perhatikan alur ini:
fun add(x: Int, y: Int): Int
│
│ ::add
↓
val operation = ::add
│
│
↓
operation(5, 5)
│
↓
add(5, 5)
│
↓
10
Sekarang kalau function dikirim ke function lain:
::add
│
↓
printResult(
operation,
a,
b
)
│
↓
operation(a, b)
│
↓
add(a, b)
32. Ini Akan Menjadi Dasar untuk Lambda
Lesson ini kemungkinan akan dilanjutkan ke lambda expression.
Misalnya nanti kamu bisa menulis function tanpa memberi nama:
val add = { a: Int, b: Int -> a + b }
Sekarang kita tidak sedang memakai:
function bernama + ::
tetapi membuat function value secara langsung.
Namun secara konsep, ini masih berhubungan dengan:
(Int, Int) -> Int
Jadi pemahaman lesson ini sangat penting sebelum lambda.
33. Perbedaan Function Reference dengan Lambda
Untuk sekarang cukup lihat:
Function reference
val operation = ::add
Kita menunjuk ke function yang sudah ada.
Lambda
val operation = { a: Int, b: Int -> a + b }
Kita membuat function value baru secara langsung.
Keduanya bisa memiliki function type yang sama:
(Int, Int) -> Int
Ini nanti akan sangat penting.
34. Contoh yang Lebih Realistis
Misalnya kita memiliki:
fun calculate(
operation: (Int, Int) -> Int,
a: Int,
b: Int
): Int {
return operation(a, b)
}
Lalu:
fun add(a: Int, b: Int): Int {
return a + b
}
fun multiply(a: Int, b: Int): Int {
return a * b
}
Kita bisa:
val result1 = calculate(::add, 10, 5)
val result2 = calculate(::multiply, 10, 5)
println(result1)
println(result2)
Output:
15
50
calculate() sama.
Yang berubah hanyalah function yang dikirim:
::add
atau:
::multiply
Ini adalah alasan function-as-value sangat powerful.
35. Yang Perlu Diluruskan dari Subtitle
Ada beberapa bagian subtitle yang penting untuk dikoreksi.
1. “method reference operator is two dots”
Subtitle tampaknya menyebut simbol yang membingungkan.
Yang benar untuk function reference adalah:
::add
yaitu dua titik dua, bukan ...
Perhatikan:
.. → range/operator lain
:: → callable/function reference
Jangan sampai tertukar.
2. t bukan return type
Kalau:
val t = ::add
t adalah variable yang merujuk pada function.
Function type-nya:
(Int, Int) -> Int
3. println(t) bukan mencetak hasil function
Untuk mendapatkan hasil:
println(t(5, 5))
Bukan:
println(t)
t sendiri adalah function reference/value.
4. “Function is simply another data type”
Ini adalah mental model yang berguna, tetapi jangan ditafsirkan terlalu harfiah.
Lebih tepat untuk tahap ini:
Kotlin memiliki function types, sehingga function dapat diperlakukan sebagai value: direferensikan, disimpan, dan dikirim sebagai argument.
5. “Function inside function”
Subtitle menggunakan istilah seperti function di dalam function.
Yang sebenarnya terjadi di contoh ini bukan nested declaration function.
Yang terjadi adalah:
sebuah function dikirim sebagai argument ke function lain.
Itulah konsep higher-order function.
36. Hubungkan dengan Materi Sebelumnya
Sekarang semua materi mulai tersambung:
Function
↓
Parameter
↓
Return value
↓
Function type
↓
Function reference (::)
↓
Function disimpan dalam variable
↓
Function dikirim sebagai argument
↓
Higher-order function
Contoh final:
fun add(a: Int, b: Int): Int {
return a + b
}
fun printResult(
operation: (Int, Int) -> Int,
a: Int,
b: Int
) {
val result = operation(a, b)
println(result)
}
fun main() {
val operation = ::add
printResult(operation, 10, 20)
}
Output:
30
37. Cara Membaca Program Ini
Mulai dari main():
val operation = ::add
Artinya:
simpan referensi ke function
addke dalamoperation.
Kemudian:
printResult(operation, 10, 20)
Artinya:
operation → function add
10 → a
20 → b
Masuk ke:
fun printResult(
operation: (Int, Int) -> Int,
a: Int,
b: Int
)
kemudian:
val result = operation(a, b)
Karena:
operation → add
maka secara konsep:
val result = add(10, 20)
hasil:
30
dan:
println(result)
mencetak:
30
38. Mental Model Paling Mudah
Bayangkan function adalah alat.
Misalnya:
ADD
Kita bisa langsung memakai alat:
add(5, 5)
atau kita bisa mengambil referensinya:
::add
dan memasukkan alat tersebut ke variable:
operation
Kemudian variable itu bisa dikirim ke function lain:
calculate(operation, 5, 5)
Jadi:
FUNCTION
↓
bisa direferensikan
↓
bisa disimpan
↓
bisa dikirim
↓
bisa dipanggil
39. Cheat Sheet Lesson Ini
Function biasa
fun add(a: Int, b: Int): Int {
return a + b
}
Memanggil function
add(5, 5)
Function reference
::add
Menyimpan function reference
val operation = ::add
Function type
(Int, Int) -> Int
Memanggil function melalui variable
operation(5, 5)
Function sebagai parameter
fun calculate(
operation: (Int, Int) -> Int,
a: Int,
b: Int
): Int {
return operation(a, b)
}
Mengirim function
calculate(::add, 5, 5)
40. Inti Lesson dalam Satu Gambar Mental
FUNCTION
│
│ ::add
↓
┌──────────────────┐
│ variable │
│ operation │
└──────────────────┘
│
│
↓
function lain
│
↓
operation(5, 5)
│
↓
add(5, 5)
│
↓
10
Jadi kalimat terpenting untuk lesson ini adalah:
Di Kotlin, function memiliki function type sehingga kita bisa mengambil referensi ke sebuah function dengan
::, menyimpannya dalam variable, memanggilnya melalui variable tersebut, dan bahkan mengirim function tersebut sebagai argument ke function lain.
Dan bentuk yang paling penting untuk kamu hafalkan saat ini:
fun add(a: Int, b: Int): Int {
return a + b
}
val operation: (Int, Int) -> Int = ::add
println(operation(5, 5))
Hasilnya:
10
Kalau kamu sudah memahami ::add → (Int, Int) -> Int → operation(5, 5), berarti inti lesson ini sudah kamu tangkap.