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:
1// Generic function in Java 2 3fun <T> testGenerics(value: T) { 4 println(value) 5} 6fun main() { 7 testGenerics<String>("Learning Generics!") // "Learning Generics!" 8 testGenerics<Int>(100) // 100 9 testGenerics<Boolean>(true) // true 10} 11
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:
1 // Print type of T 2 3 fun <T> testGenerics(value: T) { 4 println(value) 5 println("Type of T: ${T::class.java}") 6} 7
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.
1// Passing the class of T as a parameter to the function testGenerics. 2 3fun <T> testGenerics(classType: Class<T>, value: T) { 4 println(value) 5 println("Type of T: ${classType}") 6} 7fun main() { 8 testGenerics<String>(String::class.java, "Learning Generics!") 9 testGenerics<Int>(Int::class.java, 100) 10 testGenerics<Boolean>(Boolean::class.java, true) 11} 12
It will finally give the output as,
1Learning Generics! 2Type of T: class java.lang.String 3100 4Type of T: int 5true 6Type of T: boolean 7
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:
1 // Using Inline function with reified keyword to access type of T 2 3inline fun <reified T> testGenerics(value: T) { 4 println(value) 5 println("Type of T: ${T::class.java}") 6} 7fun main() { 8 testGenerics<String>("Learning Generics!") 9 testGenerics<Int>(100) 10 testGenerics<Boolean>(true) 11} 12
The output for the above code is:
1Learning Generics! 2Type of T: class java.lang.String 3100 4Type of T: class java.lang.Integer 5true 6Type of T: class java.lang.Boolean 7
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.
1// Without reified keyword 2 3fun showMessage(payment: Boolean): Boolean { 4 return payment 5} 6fun showMessage(payment: Boolean): String { 7 return "Sorry!! You don’t have enough balance to proceed "; 8} 9
But if you execute the code, it will show the following errors.
1» 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 2» 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 3
This problem can be solved by using reified keywords:
1 // Without reified keyword and inline function 2 3inline fun<reified T> showMessage(payment: Boolean): T { 4 return when (T::class) { 5 Boolean::class -> payment as T 6 String::class -> "Sorry!! You don’t have enough balance to proceed " as T 7 else -> "Please enter valid type" as T 8 } 9} 10fun main() { 11 val booleanPayment: Boolean = showMessage(true) // returning boolean value 12 val stringMessage: String = showMessage(true) // returning string value 13 println("Your Payment: $booleanPayment \nMessage: $stringMessage") 14} 15
Here is the output of the above code,
1Your Payment: true 2Message: Sorry!! You don’t have enough balance to proceed 3
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.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.