Zoom Webinar: Learn and enhance your TypeScript skills | 28th March 2023 | 10 AM PST [10:30 PM IST] Register here
Education

Kotlin Generics: Reified Type Parameter with Inline Function

logo

DhiWise

July 16, 2021
image
Author
logo

DhiWise

{
July 16, 2021
}

Most programming languages use Generics but accessing type info in the generic function has some limits as type information is erased by the compiler during compile-time. Kotiln handles this issue in the best possible way using Inline functions with a reified type parameter.

Kotlin Generics

About Generics

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.

How to access type information in generics

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:

// Generic function in Javafun< T > testGenerics(value: T) {println(value)}fun main() {testGenerics< String >(“Learning Generics!”) // “Learning Generics!”testGenerics< Int >(100) // 100testGenerics< Boolean >(true) // true}

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:

// Print type of Tfun< T > testGenerics(value: T) {println(value)println(“Type of T: ${T::class.java}”)}

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.

// 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)}

It will finally give the output as,
Learning Generics!
Type of T: class java.lang.String
100
Type of T: int
true
Type of T: boolean

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.

Reified keyword in Kotlin

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:

// Using Inline function with reified keyword to access type of Tinline 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)}

The output for the above code is:

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

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.

Function overloading with Reified keyword

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.

// Without reified keywordfun showMessage(payment: Boolean): Boolean {return payment}fun showMessage(payment: Boolean): String {return “Sorry!! You don’t have enough balance to proceed “;}

But if you execute the code, it will show the following errors.

» 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

This problem can be solved by using reified keywords:

// Without reified keyword and inline functioninline fun< reified T > showMessage(payment: Boolean): T {return when (T::class) {Boolean::class -> payment as TString::class -> “Sorry!! You don’t have enough balance to proceed ” as Telse -> “Please enter valid type” as T}}fun main() {val booleanPayment: Boolean = showMessage(true) // returning boolean valueval stringMessage: String = showMessage(true) // returning string valueprintln(“Your Payment: $booleanPayment \nMessage: $stringMessage”)}

Here is the output of the above code,

Your Payment: true
Message: Sorry!! You don’t have enough balance to proceed

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.

DhiWise is the new edge platform that empowers developers to build high-quality web and mobile applications. Its ultra-modern features and technologies fast-track the process of app development so that you can finish your month’s work in weeks.

With Dhiwise Kotlin builders, you can easily generate your source code, build UI components, and much more.
It’s all so easy now!!

What to know how? Try DhiWise Kotlin Builder!!