Reification of the erased

Kotlin Vocabulary, Reified

Murat Yener
May 21, 2020 · 4 min read

The title might sound like a B-rated horror movie, but in reality, Kotlin’s “reified” keyword helps you do things that were not possible before. Generics provide type safety and help you avoid explicit type casts. Generics extend the type system to allow a type or method to operate on objects of various types while providing compile-time type safety. On the other hand, generics can be limiting when you need to access type info in a generic function, and the compiler tells you the info doesn’t exist!

This missing type info is a result of how generics are implemented in the JVM (hint: type erasure, which we’ll discuss later). As a workaround, you can access the deleted generic type by passing the class of the generic type as a parameter of the function.

This isn’t too bad, but as you know from other posts in the Kotlin Vocabulary series, Kotlin hates boilerplate code and aims to help you write less code! Kotlin addresses this problem with a unique keyword, reified, that lets you access the type info from within a generic function. If you are familiar with how generics work, you might be asking how this is even possible. Let’s see how :)

Generics

Before generics were added to Java with version 5.0, type info didn’t exist in collections. This means there is no indication if an ArrayList is an ArrayList of String, Integer, or any other object type.

Without generics, each time you want to access an object in a collection you need to perform an explicit cast. Plus, there is no guard against invalid casts which result in runtime exceptions.

To address this, generics were added in Java 5. With generics, you can define a specific type for a collection, and the compiler will warn you if you try to add any other type. Also, you don’t need to perform explicit casts, which might result in runtime exceptions.

Generics are implemented with a trick called type erasure. Since there was no type info before Java 5, the Java compiler first replaces all type info with a base Object type and adds the necessary type casts. Type erasure allows both compile-time type safety by providing type information to the compiler as well as backwards compatibility by keeping the byte code the same as on previous Java versions. Meanwhile, type erasure can be limiting when you need the type info in a generic function.

Reified

Now let’s see how reified manages to access type info at runtime that should have been erased at compile time. To tackle this problem, reified makes use of inline functions. If you’re unfamiliar with inline functions, read this blog post.

To recap, if a function is marked as inline, the Kotlin compiler will copy the function body to every place where it is used. One advantage of this is that the compiler is also free to modify the function body as it’s being copied over. To use reified parameter types, you first need to make the function inline and then add the reified keyword to the generic parameter.

Let’s take a look at what is happening under the hood in the decompiled Java code. When there is a call to the inline function with a reified type, the compiler will copy the function body and replace generic types with the actual declared type. As a result, you don’t need to pass the class to access the type info.

Reified can be used only with inline functions, so the same rules that apply to inline functions also apply to reified. Also, keep in mind that reified functions can not be accessed from Java. Java doesn’t support inlining, and without inlining, generic parameters can not escape being erased by the compiler.

Reified also allows overloading functions to return generic types. For example, the following function can return an Int or Float.

Normally, a function can not be overloaded with the same input and have different return types. With inline functions, once again the compiler can replace the generic return type with the expected type while copying the function body. If you take a look at the decompiled Java Code, the compiler uses an Integer type for the intCall variable and uses Float for the floatCall variable.

Reified allows you to do things with generics which were previously not possible due to lack of type info at runtime. Use reified when you need the class type info in your inline functions or to overload generic return types. Reified doesn’t introduce any performance penalties, but inlining a large function can. Since a function needs to be inlined in order to use reified types, don’t forget to keep your reified functions short to avoid performance penalties and follow the best practices for inline functions.

Android Developers

The official Android Developers publication on Medium

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store