
Build 10x products in minutes by chatting with AI - beyond just a prototype.
What are generics in Kotlin?
Why is type information erased in generics?
How did developers access type information in generics before Kotlin's reified keyword?
What are the benefits of using the reified keyword?
What are the limitations of the reified keyword?
What is function overloading?

In most programming languages, Generics are used to provide a general implementation of the class, functions, or some method which means you can write the implementation part once and use it for various data types.
Generic parameters in Java are a great way to provide type safety and avoid explicit type casting. It ensures compile-time type safety by allowing a type or a method to operate on objects of various types.
On the other hand, Generics can be limited when accessing type information in generic functions as it gets erased at the time of compilation.
The problem can be solved by explicitly passing the class of generic type as a parameter of the function, but it can potentially increase the number of lines of code both in Java and Kotlin if there are more types and you need to pass each of them.
Let us understand this through an example,
Suppose you have written the following code for the Generic function:
Here in the code snippet, you can see the generic function can be used for any type of variable, i.e. String, Int, Boolean, Long, etc.
However, if you want to know the type of T used in the testGenerics function, the code is as follows:
When you run the above code, you will receive the following error:- **“Cannot use ‘T’ as a reified type parameter. Use a class instead.” **
This is because the type is already erased at compile-time, and if you want to access the type of T, you must pass the class of T as a parameter to the function testGenerics, as shown below.
It will finally give the output as,
But what if you have multiple types and want to access each one separately?
In such a case, you need to pass the class of T as a parameter to the function for each type, which is time-consuming, repetitive, and adds lots of boilerplate code to your application. Therefore, passing the class of T is not an optimal way to access each type.
Kotlin provides a better solution to this problem using reified types.
The keyword reified enables you to access the type of info at runtime that should have been erased during code compilation. The reified keyword uses an inline function to perform this task.
The Kotlin compiler can detect inline functions and copy the function body to every location where it is used in the application. It helps the compiler to freely modify the function body as it’s being copied over.
The following code sample shows how we can use the reified keyword in the in Inline function:
The output for the above code is:
Here you can see with the inline function and reified keyword; we do not need to pass the class as a parameter to the function every time.
This feature is only available in Kotlin because Java does not provide support for the Inline function and we can not use reified keywords without the inline function.
Other than the above, reified also enables function overloading and returns generic types.
Consider the following scenario: you want to keep the function’s name, number, and type the same but want to return it differently.
In the following example, we want to print the message if there is no cash in the account and if there is cash, you can make the payment.
But if you execute the code, it will show the following errors.
This problem can be solved by using reified keywords:
Here is the output of the above code,
Without an inline function, a function cannot be overloaded with the same input and produce the different return types. On the other hand, the inline function compiler can replace the generic return type with the required type by copying the function body.
Kotlin aims to remove boilerplate code, and therefore it provides the most classy way to deal with issues discussed above by utilizing inline functions and the reified keyword.
Building an Android app is never easy; developers must consider numerous factors to achieve high quality and performance.
// Generic function in Java
fun <T> testGenerics(value: T) {
println(value)
}
fun main() {
testGenerics<String>("Learning Generics!") // "Learning Generics!"
testGenerics<Int>(100) // 100
testGenerics<Boolean>(true) // true
}
// Print type of T
fun <T> testGenerics(value: T) {
println(value)
println("Type of T: ${T::class.java}")
}
// Passing the class of T as a parameter to the function testGenerics.
fun <T> testGenerics(classType: Class<T>, value: T) {
println(value)
println("Type of T: ${classType}")
}
fun main() {
testGenerics<String>(String::class.java, "Learning Generics!")
testGenerics<Int>(Int::class.java, 100)
testGenerics<Boolean>(Boolean::class.java, true)
}
Learning Generics!
Type of T: class java.lang.String
100
Type of T: int
true
Type of T: boolean
// Using Inline function with reified keyword to access type of T
inline fun <reified T> testGenerics(value: T) {
println(value)
println("Type of T: ${T::class.java}")
}
fun main() {
testGenerics<String>("Learning Generics!")
testGenerics<Int>(100)
testGenerics<Boolean>(true)
}
Learning Generics!
Type of T: class java.lang.String
100
Type of T: class java.lang.Integer
true
Type of T: class java.lang.Boolean
// Without reified keyword
fun showMessage(payment: Boolean): Boolean {
return payment
}
fun showMessage(payment: Boolean): String {
return "Sorry!! You don’t have enough balance to proceed ";
}
» Conflicting overloads: public fun showMessage(payment: Boolean): Boolean defined in root package in file File.kt, public fun showMessage(payment: Boolean): String defined in root package in file File.kt
» Conflicting overloads: public fun showMessage(payment: Boolean): Boolean defined in root package in file File.kt, public fun showMessage(payment: Boolean): String defined in root package in file File.kt
// Without reified keyword and inline function
inline fun<reified T> showMessage(payment: Boolean): T {
return when (T::class) {
Boolean::class -> payment as T
String::class -> "Sorry!! You don’t have enough balance to proceed " as T
else -> "Please enter valid type" as T
}
}
fun main() {
val booleanPayment: Boolean = showMessage(true) // returning boolean value
val stringMessage: String = showMessage(true) // returning string value
println("Your Payment: $booleanPayment \nMessage: $stringMessage")
}
Your Payment: true
Message: Sorry!! You don’t have enough balance to proceed