Function Kotlin

Muhammad Fajri
Tuesday, 13 April 2021

Bismillahirrahmanirrahim.

Sebelumnya kita sudah mengenal sebuah function yang wajib dibuat agar program bisa berjalan yaitu function main(). Function sendiri yaitu sebuah blok kode yang sengaja dibuat dalam program agar dapat digunakan berulang-ulang.

Function pada Kotlin hampir sama dengan method Java, meskipun perilakunya lebih dekat seperti JavaScript. Karena function di Kotlin lebih dari sekedar nama collection atau statement. Di Kotlin kita dapat menggunakan function sebagai variabel, nilainya dapat diteruskan sebagai parameter pada function yang lain, dan dapat mengembalikan function dari function yang lain.

Deklarasi Function

Function dapat dituliskan di 3 tempat, di dalam class (disebut member function), di luar class (disebut top-level function), dan dituliskan di dalam function yang lain (disebut local function). Dari cara penulisan function, memicu akses tertentu pada sebuah function di mana function tersebut dibuat. Ini dinamakan sebagai function scope.

Struktur dasar penulisan function:

fun namaFunction([parameter]) [:tipe data] {
    // statement
}

fun kata kunci yang digunakan untuk mendeklarasikan function, diikuti sebuah identifier (yang merupakan nama function). Nama function diikuti tanda kurung yang dapat diisikan parameter-parameter (opsional). [:tipe data], kita dapat menuliskan tipe data yang dikembalikan oleh function (opsional) karena Kotlin dapat mengenali tipe data yang dikembalikan dengan melihat isi/ body deklarasi, sama seperti pembuatan variabel. Tapi jika dibutuhkan, kita boleh menuliskannya. Kemudian di dalam kurung kurawal ({...}) yang merupakan body dari function sebagai tempat untuk mengisikan statement-statement yang dibutuhkan.

Aturan Penulisan Nama Function

Kita dapat menuliskan nama function seperti aturan dalam bahasa Java. Aturannya yaitu:

  • Tidak boleh menggunakan reserved word atau kata kunci yang melekat/ dimiliki oleh Kotlin.
  • Tidak boleh diawali dengan bilangan.
  • Tidak boleh memuat karakter khusus.
  • Sebaiknya diberi nama sesuai dengan fungsinya, yang menandakan aksi yang akan dilakukannya.

Berikut contoh pembuatan function.

fun tampilPesan(pesan: String, hitung: Int) {
    for(i in 1..hitung) {
        println(pesan)
    }
}
fun main(args: Array<String>) {
    tampilPesan("Hai semua", 4)    
}

Output:

Hai semua
Hai semua
Hai semua
Hai semua

Dapat dilihat pada function tampilPesan() yang dibuat tidak mengembalikan nilai, utamanya dapat dilihat tidak terdapat tulisan return di dalam body dari function tersebut. Function yang seperti ini sebenarnya memiliki nilai kembalian bernama Unit namun penulisannya bersifat opsional karena Kotlin dapat mengenalinya. Unit yang dalam bahasa Java sama seperti void.

Function tampilPesan(), jika dipanggil pada function main() yaitu dengan menuliskan nama function dan mengisikan nilai bersadarkan tipe data dari parameter yang dibuat sebagai nilai yang diteruskan pada deklarasi function-nya. Nilai yang diberikan ini harus sesuai urutannya dari kiri ke kanan.

Jika ingin menuliskan nilai kembalian Unit ini, maka function diubah menjadi:

fun tampilPesan(pesan: String, hitung: Int): Unit {
    for(i in 1..hitung) {
        println(pesan)
    }
}

Sebagai perbandingan, berikut penulisan function tampilPesan() jika ditulis dalam bahasa Java. File harus disimpan dengan nama TampilPesan.java.

public class TampilPesan {
    static void tampilPesan(String pesan, int hitung) {
        for(int i=1; i <= hitung; i++) {
            System.out.println(pesan);
        }
    }
    public static void main(String []args) {
        tampilPesan("Hai semua", 4);
    }
}

Output:

Hai semua
Hai semua
Hai semua
Hai semua

Function dengan Nilai Return

Dari contoh sebelunya, kita telah membuat sebuah function tanpa nilai kembalian dan sekaligus mengenali function yang berisi parameter. Berikut ini kita buat contoh function dengan nilai kembalian, dengan menuliskan return sebagai kata kuncinya.

fun main(args: Array<String>) {
    println(getSum(listOf(1,2,3,4,5,)))
}
fun getSum(values: List<Int>): Int {
    var total = 0
    for(i in values) total += i
    return total
}

Perhatikan pada function di atas. fun getSum(values: List<Int>): Int {...}, pada function ini Int merupakan tipe data kembaliannya, ditunjukkan oleh Int setelah tanda titik dua. return total, dan di dalam body dari function getSum() dapat dilihat bahwa total sebagai nilai kembaliannya. Jika dilihat, total ini sebagai nilai integer (sebagai tipe data inference yang dikenali oleh Kotlin).

Untuk membuat tipe data kembalian dari sebuah function, tidak terbatas pada tipe data basic. Sebagai contoh, perhatikan program berikut.

fun bigSmall(a: Int, b: Int): Pair<Int, Int> {
    if(a > b) return Pair(a,b)
    else return Pair(b,a)
}
fun main(args: Array<String>) {
    var (x,y) = bigSmall(5,3)
    println(x)
    println(y)
}

Output:

5
3

Pair<Int, Int> pada kode di atas memberitahukan compiler bahwa function tersebut mengembalikan Pair. Ini merupakan class data. Jika pernah menggunakan Python sebelumnya, ini akan mengingatkan kita pada tuple.

Pada blok if, jika nilai a lebih besar dari b, maka dibuat parameter Pair dengan nilai a pada posisi pertama dan b pada posisi kedua kemudian dikembalikan nilainya saat dipanggil. Begitu pun sebaliknya, jika nilai a lebih kecil dari b, maka dibuat parameter Pair dengan nilai b pada posisi pertama dan a pada posisi kedua kemudian dikembalikan nilainya saat dipanggil. Dengan kata lain, posisi yang mana pun yang memiliki nilai lebih besar, output yang dihasilkan tetap sama, nilai yang lebih besar dicetak terlebih dahulu kemudian nilai yang lebih kecilnya jika pembuatan output programnya (println()) seperti di atas.

Pair dapat dikembalikan pada variabel melalui assignment. Hal ini memungkinkan kita untuk menyimpan banyak nilai pada banyak variabel dalam sekali assignment. Pada contoh di atas, x akan menerima posisi pertama dari nilai Pair dan y akan menerima posisi kedua dari nilai Pair.

Function Single Expression

Kadang kita sering membuat function yang sangat sederhana. Kadang terdapat situasi di mana statement return, kurung kurawal, dan tipe data kembaliannya dapat dihilangkan. Blok kode yang dibuat cukup sederhana, misal hanya satu baris. Jika berada dalam kondisi ini kita dapat membuat single expression function (hanya berisi satu baris kode). Contoh programnya:

fun tampilUmur(umur: Int) = umur

fun tampilNama(nama: String) = nama

fun main(args: Array<String>) {

    var biodata = """
    Nama saya ${tampilNama("Ahmad")}.
    Umur ${tampilUmur(18)} tahun.
    """.trimIndent()

    println(biodata)
}

Output:

Nama saya Ahmad.
Umur 18 tahun.

Perhatikan program di atas. Single function expression yang dibuat tidak terdapat return type, return value, dan kurung kurawal. Return type tidak dituliskan karena compiler dapat mengenalinya berdasarkan inference, namun jika ingin menuliskannya juga boleh. Return value tidak dituliskan karena nilai yang di-assign otomatis menjadi nilai kembaliannya. Kurung kurawal tidak dituliskan karena sudah terdapat operator assignment yaitu operator = (sama dengan) sebagai gantinya.

Untuk outputnya sendiri kita menggunakan string tamplate literal untuk memberikan nilai pada fungsi tanpa perlu dibuatkan variabel. Jika ingin dibuatkan variabel juga tidak apa-apa. Untuk trimIndent() ini berfungsi untuk menghapus indent yang dibuat dalam string template.

Default Argument

Di Kotlin, parameter dari function wajib diisi saat function-nya dipanggil. Namun, kita dapat memberikan nilai default pada parameter. Dengan demikian, saat memanggil function tersebut, kita tidak wajib memberikan nilai pada parameternya.

Contoh function-nya:

fun connectToDb(hostname: String = "localhost",
                username: String = "mysql",
                password: String = "rahasia") {
}

Perhatikan bahwa kita meng-assign “localhost”, “mysql”, dan “rahasia” pada masing-masing parameter hostname, username, dan password. Function ini dapat ditimpa menjadi seperti:

connectToDb("komputerku", "root")

Kemampuan Kotlin untuk menyediakan argumen default pada function sehingga dapat mencegah kita untuk membuat function yang overload. Di Java kita tidak dapat melakukannya, itulah mengapa kita harus membuat cara untuk meng-overload sebuah method. Di Kotlin pun kita dapat melakukannya, namun kita cukup berterima kasih dengan adanya parameter default.

Named Argument

Kadang ada function yang parameternya banyak sekali. Hal ini sangat menyulitkan saat kita akan memanggil function tersebut, kita harus benar-benar tahu urutan parameternya. Di Koltin, memiliki fitur yang namanya Named Argument yaitu fitur dimana kita dapat menyebutkan nama parameter saat memanggil function. Dengan demikian, kita tidak wajib mengetahui posisi tiap parameter.

Contoh programnya:

fun fullName(firstName: String,
             middleName: String,
             lastName: String) {
    println("Hello $firstName $middleName $lastName")
}
fun main() {
    fullName(firstName = "Eko",
             lastName = "Khannedy",
             middleName = "Kurniawan")
}

Output:

Hello Eko Kurniawan Khannedy

Untuk pemanggilan function, nama pada parameter pertama dapat dihilangkan, namun parameter setelahnya tidak bisa seperti itu. Untuk contoh di atas, kita dapat memanggil function-nya menjadi:

    fullName("Eko",
             lastName = "Khannedy",
             middleName = "Kurniawan")

Variable Number of Arguments (Varargs)

Varargs artinya datanya bisa menerima lebih dari satu input, atau anggap saja semacam Array. Input yang ada dapat berubah-ubah (integer, string, atau yang lainnya). Parameter yang berada di posisi terakhir memiliki kamampuan dijadikan sebuah varargs. Perbedaan parameter biasa dengan tipe data Array yaitu jika parameter tipe Array, kita wajib membuat array terlebih dahulu sebelum mengirimkan ke function. Jika parameter menggunakan varargs, kita bisa langsung mengirim datanya, jika lebih dari satu, cukup gunakan tanda koma.

Contoh programnya:

fun<T> manyParams(vararg va: T) {
    for (i in va) println(i)
}
fun main(args: Array<String>) {
    manyParams(1,2,3,4,5)
    manyParams("From", "Gallifrey", "to", "Trenzalore")
    manyParams(*args)
    manyParams(*"Hello there".split(" ").toTypedArray())
}

vararg kata kunci yang memungkinkan kita untuk menerima banyak parameter pada function. Pada fungsi tersebut kita dapat meneruskan nilai integer, string, atau yang lainnya sebanyak yang kita inginkan.

manyParams(*args), seperti di Java, kita dapat meneruskan array pada function yang menerima variabel arguments. Kita memerlukan spread operator (*) untuk untuk membognkar array. Ini sama seperti meneruskan elemen array satu per satu jika secara manual.

Function split() akan mengembalikan nilai ArrayList, dapat dikonversi ke Array, kemudian gunakan spread operator agar dapat diteruskan ke function vararg.

Extension Function

Di Java, jika kita perlu menambahkan fungsionalitas pada sebuah class, kita dapat menambahkan method pada class itu atau melakukan extend melalui inheritance. Extension function di Kotlin memungkinkan kita untuk menambahkan perilaku pada class yang sudah ada, dengan kata lain tipe data yang sudah ada, tanpa menggunakan inheritance. Harap bijak menggunakan extension function ini karena jika terlalu banyak, program akan sulit dimengerti.

Untuk membuat extension function, kita cukup menambahkan tipe data pada nama function-nya diikuti tanda titik (.). Dan untuk mengakses datanya, kita gunakan kata kunci this.

Contoh programnya:

fun String.hello(): String {
    return "Hello $this"
}
fun main() {
    val name: String = "Eko"
    val hello: String = name.hello()
    println(hello)
}

Atau agar lebih sederhana, kita buat penulisan programnya menjadi:

/* single expression function
   combined with extension function
*/
fun String.hello() = "Hello $this"

fun main() {
    val name = "Eko" // type inference
    val hello = name.hello() // so this one
    println(hello)
}

Output:

Hello Eko

Function Infix Notation

Infix Notation adalah operasi yang biasa dilakukan di operasi matematika, dimana kita dapat melakukan operasi terhadap dua data. Hampir semua operasi matematika adalah infix notation. Di Kotlin, kita juga bisa membuat function infix notation. Untuk mengunakan function infix notation, tidak wajib menggunakan tanda titik (.).

Pada function infix notation, terdapat syarat yang harus dipenuhi yaitu:

  • Harus sebagai function member (bagian dari class) atau extension function.
  • Hanya menerima satu parameter.
  • Parameter tidak boleh varargs dan tidak boleh memiliki nilai default.

Contoh programnya:

/* extension function
   combined with infix function
*/
infix fun String.to(type: String): String {
    if(type == "UP") return this.toUpperCase()
    else return this.toLowerCase()
}
fun main() {
    val result: String = "Eko" to "UP"
    println(result)
}

Perhatikan program di atas. Untuk membuat sebuah function menjadi infix function, ditambahkan kata kunci infix di awal pembuatan function. Di sini dibuat function dengan nama to yang meneruskan sebuah parameter dengan nama type. Di dalam body dari function dilakukan evaluasi nilai dari type, jika nilai yang diteruskan yaitu UP maka nilai result (lihat bagian function main()) yaitu Eko menjadi kapital, sebaliknya semuanya akan menjadi huruf kecil. Terakhir, saat pemanggilan function (to "UP"), nilainya tidak diapit oleh kurung kurawal lagi.

Contoh lain, tanpa infix function:

fun main() {
    val john = Person("John Doe")
    john.say("Hello world")
}
class Person(val name: String) {
    fun say(message: String) = println("$name is saying $message")
}

Dengan infix function:

fun main() {
    val john = Person("John Doe")
    john say "Hello world"
}
class Person(val name: String) {
    infix fun say(message: String) = println("$name is saying $message")
}

Infix function jika digunakan secara bijaksana, memungkinkan kode yang dibuat menjadi lebih intuitif karena dapat menyembunyikan logika program di belakang sintaks kata kunci. Kita dapat membuat beberapa urutan meta-language dengan infix notation, tetapi hati-hati untuk tidak melakukannya secara berlebihan.

Referensi

  1. Modul Pemrograman Mobile (Mobile Programming).
  2. Hagos, Ted. 2018. Learn Android Studio 3 with Kotlin: Efficient Android App Development. Apress: Manila.