Type erasure membuat type parameter generic hilang saat runtime, sehingga kita tidak dapat melakukan if (item is T). Untuk banyak kasus, ini cukup membatasi — kita mungkin ingin menulis function yang memfilter elemen berdasarkan tipe, atau function yang mencetak nama tipe generic. Kotlin menyediakan reified type parameters untuk mengatasi batasan ini. Reified hanya bekerja pada function inline karena kompilator menggabungkan function ke dalam pemanggil, sehingga type argument konkret tersedia di lokasi pemanggilan. Pada chapter ini kita akan mempelajari cara mendeklarasikan function dengan reified, melihat apa yang menjadi mungkin, serta memahami batasan yang masih tersisa.
Apa Itu Reified #
Keyword reified pada type parameter berarti kompilator mempertahankan informasi tipe generic di lokasi pemanggilan. Karena function inline disalin ke setiap pemanggil, kompilator mengetahui type argument konkret di setiap titik pemanggilan. Hal ini memungkinkan operasi yang biasanya dilarang oleh type erasure.
inline fun <reified T> namaTipe(): String = T::class.simpleName ?: "<anonim>"Function namaTipe<Int>() mengembalikan "Int" karena kompilator menggabungkan function dengan T = Int ke pemanggil. Tanpa reified dan inline, type erasure akan menghapus T dan function tidak akan tahu tipe apa yang dipakai.
Mengapa Reified Memerlukan Inline #
Function non-inline tidak dapat memiliki reified type parameter karena pemanggil function tidak mengetahui type argument yang dipakai oleh pemanggil. Function inline disalin ke pemanggil, sehingga type argument yang ditulis pemanggil tersedia di lokasi kode. Hal ini menjelaskan mengapa reified selalu didahului oleh inline.
Operasi yang Memungkinkan Reified #
Reified membuka banyak operasi yang biasanya dilarang oleh type erasure:
| Operasi | Tanpa Reified | Dengan Reified |
|---|---|---|
item is T | Tidak | Ya |
T::class.simpleName | Tidak | Ya |
Array<T> (kreasi) | Tidak | Ya (untuk size) |
javaClass<T>() | Tidak | Ya |
| Refleksi tipe generic | Tidak | Ya |
Contoh Lengkap dengan Reified #
Mari kita lihat beberapa penggunaan reified dalam praktek:
// Chapter: reified Type Parameters
// inline fun <reified T>: type parameter tetap tersedia saat runtime.
inline fun <reified T> namaTipe(): String = T::class.simpleName ?: "<anonim>"
inline fun <reified T> adalahTipe(item: Any): Boolean = item is T
inline fun <reified T> filterTipe(daftar: List<Any>): List<T> {
val hasil = mutableListOf<T>()
for (e in daftar) {
if (e is T) hasil.add(e)
}
return hasil
}
inline fun <reified T> buatList(kosong: T): List<T> {
return listOf(kosong, kosong)
}
class Token(val nilai: String)
data class Pesanan(val id: Int, val nominal: Int)
fun main() {
println("Tipe Int: ${namaTipe<Int>()}")
println("Tipe String: ${namaTipe<String>()}")
println("Tipe Token: ${namaTipe<Token>()}")
println("Tipe Pesanan: ${namaTipe<Pesanan>()}")
println("10 adalah Int? ${adalahTipe<Int>(10)}")
println("10 adalah String? ${adalahTipe<String>(10)}")
println("\"Halo\" adalah String? ${adalahTipe<String>("Halo")}")
val campur: List<Any> = listOf(1, "dua", 3, "empat", 5.0, "enam")
val hanyaString = filterTipe<String>(campur)
println("String saja: $hanyaString")
val hanyaInt = filterTipe<Int>(campur)
println("Int saja: $hanyaInt")
val arr = buatList("[kosong]")
println("Daftar String default: $arr")
val arrInt = buatList(0)
println("Daftar Int default: $arrInt")
}Output yang Dihasilkan:
Tipe Int: Int
Tipe String: String
Tipe Token: Token
Tipe Pesanan: Pesanan
10 adalah Int? true
10 adalah String? false
"Halo" adalah String? true
String saja: [dua, empat, enam]
Int saja: [1, 3]
Daftar String default: [[kosong], [kosong]]
Daftar Int default: [0, 0]Mari kita telaah baris-baris kode di atas:
inline fun <reified T> namaTipe(): functioninlinedengan type parameterreified. Function mengembalikan nama sederhana kelasTmelalui refleksi.namaTipe<Int>(): pemanggil menentukan type argumentInt. Karena function inline, kompilator menggantiTdenganIntdi lokasi pemanggil, sehinggaT::class.simpleNamemenjadiInt::class.simpleName.inline fun <reified T> adalahTipe(item: Any): Boolean = item is T: function yang memeriksa apakahitembertipeT. Tanpareified, operasiis Tdilarang karena type erasure.adalahTipe<Int>(10): pemanggilan valid. Kompilator menggantiTdenganInt, sehingga pemeriksaan menjadiitem is Int.inline fun <reified T> filterTipe(daftar: List<Any>): List<T>: function generic yang memfilter elemen berdasarkan tipe. Hasil adalahList<T>— list berisi elemen yang dipastikan bertipeT.filterTipe<String>(campur): kompilator menggantiTdenganString. Setiap elemen diperiksa denganis String, dan yang lolos dimasukkan kehasil.inline fun <reified T> buatList(kosong: T): List<T>: function sederhana yang membuat list dengan dua elemen identik. Tidak benar-benar memanfaatkanreified, tetapi ditunjukkan sebagai contoh tambahan.buatList("[kosong]"): kompilator menyimpulkanT = Stringdari argumen"[kosong]". HasilnyaList<String>berisi dua elemen string.
Batasan Reified #
Meskipun reified membuka banyak kemungkinan, ada batasan yang masih berlaku:
- Tidak dapat dipakai pada class generic — hanya pada function
inline. - Tidak dapat dipakai untuk membuat array
Array<T>dengan size yang bergantung padaT— array Java memerlukan informasi tipe runtime yang reified, dan reified Kotlin tidak sepenuhnya menggantikan array reifikasi JVM. - Tidak dapat dipanggil dari kode Java — Java tidak memahami
reified.
Untuk kasus yang memerlukan pemeriksaan tipe generic kompleks, kombinasikan reified dengan KClass<T> atau pustaka refleksi seperti kotlin-reflect.
Penggunaan Nyata Reified #
Reified banyak dipakai di standard library Kotlin dan library populer. Contoh paling dikenal adalah filterIsInstance<T>() pada koleksi — function inline dengan reified yang memfilter elemen berdasarkan tipe. Ktor memakai reified untuk mengekstrak parameter dari URL. Koin memakai reified untuk resolusi dependensi berbasis tipe. Pola umum ini menjadikan reified salah satu fitur Kotlin yang paling sering dijumpai dalam kode produksi.
Referensi Lanjutan #
- Reified type parameters
— panduan resmi keyword
reifiedpada inline function
Pada chapter Designing Generic APIs kita akan melihat bagaimana memadukan semua konsep generics — type parameter, bound, variance, reified — menjadi desain API yang elegan dan aman.