Author profile picture

Reified Type Parameter

Reified type parameters are type parameters that retain more characteristics of actual types than normal type parameters do.

For a gentle introduction to the topic, check out the guide, Getting Real with Reified Type Parameters.

Examples

Single Parameter

inline fun <reified T> Any.isInstanceOf(): Boolean = this is T

Here we created an extension function to wrap the more common is operator. Why is this example so magical? Because normally, compiling this is T would result in an error since the type of T is erased.

To invoke the function above, we can do something like this:

val isStringAString = "String".isInstanceOf<String>()
val isIntAString = 1.isInstanceOf<String>()

Multiple Parameters

You can specify multiple parameters as reified:

inline fun <reified T, reified U> haveSameType(first: T, second: U) = 
        first is U && second is T

You can specify that some type parameters are reified and others are not:

inline fun <reified T, U> listOfTypeOrNull(obj: U): List<T>? =
        if (obj is T) listOf(obj) else null

Extension Properties

You can also technically create an extension property that uses a reified type parameter, but it requires that the type parameter is used as the receiver type:

inline val <reified T> T.clazz
    get() = T::class.java

I haven’t been able to come up with a good use case for this, because you’ve got an actual object (this) that lets you do even more than you could do with a reified type parameter. For example, the same property could be implemented like this:

val <T : Any> T.clazz
    get() = this.javaClass

Characteristics

To specify a reified type parameter:

This second requirement also restricts where the function can go. For example, a local function (that is, a function defined inside another function) can’t be inlined.

Alternatives

Some of the main benefits of reified type parameters are:

  1. You can do type checks with is
  2. You can do casts without unchecked cast warnings
  3. You can assign class objects by appending ::class.java to the parameter name. e.g., val x = T::class.java

There are klunky workarounds that Java developers have adopted over the years to accomplish these things, involving things like reflection, or passing Class<T> objects as arguments to functions. Because reified type parameters are a more concise solution - especially when types can be inferred - they’re preferrable in most cases.

Since functions with reified type parameters must be declared inline, one disadvantage is that you’d want to keep your function small, or else your compiled code will get bloated quickly. On the other hand, writing small, focused functions is usually considered a good practice anyway.

For more info about reified type parameters, take a look at the guide, Getting Real with Reified Type Parameters.

Share this article: