Skip to main content

Kotlin Reified Types

In this lesson, we'll explore Kotlin's reified type parameters, a powerful feature that helps overcome certain limitations of generics in the JVM. If you've ever been frustrated by the inability to access type information at runtime, you're in for a treat with reified types!

Introduction to Type Erasure

Before diving into reified types, it's important to understand the concept of type erasure in the JVM. When Java code is compiled, generic type information is "erased" during the compilation process. This means that at runtime, a class like List<String> is treated simply as List. The JVM doesn't maintain information about what specific type was used when instantiating generic classes.

Let's see an example of the limitation this creates:

kotlin
fun <T> printType(value: T) {
// This won't compile!
// println("Type of value is ${T::class.java}")

// We can only do this:
println("Type of value is ${value::class.java}")
}

fun main() {
printType("Hello") // Type of value is class java.lang.String
printType(42) // Type of value is class java.lang.Integer
}

The problem is that we can't access T directly as a class because that information is lost at runtime due to type erasure.

Enter Reified Type Parameters

Kotlin provides a solution to this problem through a feature called reified type parameters. This feature allows you to access the actual type used as a generic parameter at runtime, but comes with a specific requirement: it can only be used with inline functions.

How Reified Types Work

Here's how we define and use a reified type parameter:

kotlin
inline fun <reified T> printReifiedType() {
println("Type of T is ${T::class.java}")
}

fun main() {
printReifiedType<String>() // Type of T is class java.lang.String
printReifiedType<Int>() // Type of T is class java.lang.Integer
}

Notice the key differences:

  1. The function is marked as inline
  2. The type parameter T is marked as reified
  3. We can now use T directly to access type information

Why Inline Functions?

Reified types work with inline functions because when the Kotlin compiler encounters an inline function call, it replaces the call with the actual function body, substituting the concrete types in the process. This happens at compile time, which means the type information is preserved.

Practical Examples of Reified Types

Example 1: Type-Safe Instance Checking

One common use case for reified types is checking if an object is of a specific type:

kotlin
inline fun <reified T> Any?.isInstanceOf(): Boolean {
return this is T
}

fun main() {
val value: Any = "Hello, Kotlin!"

println(value.isInstanceOf<String>()) // true
println(value.isInstanceOf<Int>()) // false
println(value.isInstanceOf<Any>()) // true
}

Example 2: Type-Safe Casting

Another practical application is creating a safe casting function:

kotlin
inline fun <reified T> Any?.safeCast(): T? {
return this as? T
}

fun main() {
val anyValue: Any = "Kotlin is awesome"

val stringValue: String? = anyValue.safeCast<String>()
val intValue: Int? = anyValue.safeCast<Int>()

println(stringValue) // Kotlin is awesome
println(intValue) // null
}

Example 3: Generic Function for API Responses

In a real-world application, reified types are often used when working with APIs and JSON parsing:

kotlin
import com.google.gson.Gson

inline fun <reified T> parseJson(json: String): T {
val gson = Gson()
return gson.fromJson(json, T::class.java)
}

data class User(val name: String, val age: Int)

fun main() {
val jsonString = """{"name":"Alice","age":30}"""

val user: User = parseJson<User>(jsonString)
println("User: ${user.name}, ${user.age}") // User: Alice, 30

val map: Map<String, Any> = parseJson<Map<String, Any>>(jsonString)
println("Map: $map") // Map: {name=Alice, age=30}
}

This example demonstrates how we can parse JSON into different types without having to specify the class explicitly each time.

Limitations of Reified Types

While reified types are powerful, they come with some limitations:

  1. Inline Functions Only: Reified type parameters can only be used with inline functions.
  2. Performance Trade-offs: Since inline functions copy the function body to each call site, overusing them can lead to larger bytecode.
  3. Cannot Be Used in Class Definitions: You cannot use reified types as class type parameters.
kotlin
// This won't compile
class ReifiedExample<reified T> {
fun printType() {
println(T::class.java)
}
}

When to Use Reified Types

Reified types are most useful when:

  • You need to check or cast to the generic type parameter at runtime
  • You need to instantiate a class using the type parameter
  • Working with reflection APIs that require class objects
  • Creating type-safe wrappers around existing APIs that use reflection

Summary

Reified type parameters in Kotlin solve one of the most significant limitations of generics in the JVM: the inability to access type information at runtime due to type erasure. By combining reified type parameters with inline functions, Kotlin allows you to use generic type parameters as if they were concrete types available at runtime.

Key points to remember:

  • Reified types are only available in inline functions
  • They allow access to type information that would normally be erased
  • Common use cases include type checking, casting, and reflection
  • They have some limitations and should be used judiciously

Additional Resources and Exercises

Resources:

Exercises:

  1. Create an inline function with a reified type parameter that filters a list to include only elements of the specified type.

  2. Implement a function that uses reified types to create a new instance of a class that has a no-argument constructor.

  3. Build a simple dependency injection system using reified types for type-safe service location.

  4. Create a function that takes a list of Any objects and returns a map where the keys are class types and values are lists of objects of those types.

By mastering reified types, you'll be able to write more type-safe and concise generic code in Kotlin!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)