Generic Class-as-a-Parameter Pattern & Reified Generics explained with sloths

mvndy
mvndy
Apr 18 · 6 min read

Writing code is an art form — while there are a ton of ways to achieve the same task, we want to write code in a way that the experience is pleasurable and that code is self-documenting. When I started first learning TornadoFX, I was just blown away at how much you could do with such little code! The code is so beautiful and so minimal, I was truly inspired — I had to see the source code responsible for the wonderful experience it had given me.

I had no idea what the hell I was looking at.

Yeah… when I saw this, I just closed my laptop.

I didn’t get it then, but that doesn’t mean I wouldn’t get it down the road. I hope this blurb will help you make progress understanding some of the really powerful things Kotlin can do!

Reified generics in Kotlin doesn’t have to be scary. The goal of this blurb is to explore multiple ways to achieve the same goal of filtering a list of mammals and printing out the result of an applied mammal fact.

Hi folks! If the text is blurry, please make sure the playback quality is set to 1080p!

Printing out Mammal Facts

In the last post, we examined higher-order functions in Kotlin. To briefly recap, a higher-order function is a function that uses a function as an argument.

mammalFactCheck passes in the method Mammal::knownSpeciesCount

This is fine for our main function, but what if we were doing complicated work in other projects? It can really add up and make code hard to read over time.

What if we were able to create the same behavior in a way that it looks a little cleaner in the main method?

Let’s say we want to print out the species count for each animal our crewCrewCrew. Let’s look at creating a function that accepts a type parameter as an argument and prints out the result.

Nice! The work is only done in one line!

Okay, that code method signature looks a little scary. Let’s break it down a little bit:

  1. Type parameter declaration: In order to use a generic method as an ordinary method, you must specify a type between angle brackets. There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, this method only wants to accept instances of Mammal or its subtypes. This is what bounded type parameters are for.
  2. Type parameter used in the receiver type: This function is an extension function for a List of type T. Whatever we pass in as T is designated by the type parameter declaration, if there is one.
  3. Type parameter used in the return type: We expect to return a List of type T, or whatever we end up passing in as T. In our case, we expect to return a List of the Mammal type or the subtype of Mammal.

Sure, there’s a lot going on in this function. Don’t worry, you will start seeing it after looking at a couple more examples. But this -

crewCrewCrew.printAllAnimalResults(Mammal::knownSpeciesCount)

Is certainly an upgrade from this -

crewCrewCrew.forEach {
println("${it.javaClass.name} -
${
Mammal.factCheck(it, Mammal::factCheck}")
}

Let’s see what else we can do with generics in Kotlin!

Generic Class-as-a-Parameter Pattern

Let’s look at another problem. What if we wanted to print out the species count for our crewCrewCrew, but this time, we filter the results by a particular species of Mammal?

This isn’t bad, but it’s a lot of work being done in the main method. We can pull this work out into a method that accepts a list and a clazz type parameter.

Generic Class-as-a-Parameter Pattern

In Java, if we try to get the Class of the type parameter T, the compiler complains: “Cannot use ‘T’ as reified type parameter. Use a class instead.”

As a workaround, the Class of T can be made a method parameter, which then used as an argument to printAnimalResultFilter. This works and is a common pattern in generic Java code.

Generic Class-as-a-Parameter Pattern

Our main method looks better, but admittedly, our new method call in the function is…. unsightly.

printAnimalResultFiltered(Sloth::class.java, crewCrewCrew, Mammal::knownSpeciesCount)

This is where reified generics comes in.

Reified Generics in Kotlin

Generics on the JVM are normally implemented through type erasure, meaning generic type arguments of a function is not preserved at runtime. To solve this, Kotlin may use a reified type parameter that can only be used with inline functions.

When an inline function is compiled, its bytecode along with the bytecode of a lambda passed to the function is inserted directly into the code of the calling function to prevent overhead. The effect is that you can pass functions through parameters in a way that the type arguments can’t be erased, or reified.

A reified generic type parameter ends up taking our Generic Class-as-a-Parameter Pattern signature from this:

fun <T: Mammal> printAnimalResultFiltered(
clazz: Class<T>,
list: List<Mammal>,
factCheck: Mammal.() -> Int
): List<Mammal> {...}

to this:

inline fun <reified T: Mammal> printAnimalResultFiltered(
list: List<Mammal>,
factCheck: Mammal.() -> Int
): List<Mammal> {...}

The inline keyword is what is responsible for telling the compiler to replace every call to the function with the actual code implementation the function in the bytecode.

This is a really clever way for Kotlin to workaround the JVM issue by maneuvering the underlying bytecode! Really, Kotlin is just a language that is a bunch of workarounds for annoyances in the JVM.

Our reified function now makes our main function look like this:

The idea is that you can move that class parameter into the <> in your function call. Very nice!

printAnimalsResultFiltered<Sloth>(crewCrewCrew, Mammal::knownSpeciesCount)

Creating List extension functions with reified generic parameters

It looks better than before, but I’m still not crazy about using a list as a parameter. What if we created a List extension function? Creating an extension List function using the generic class-as-a-parameter looks like this:

List Extension function with the Generic Class-as-a-Parameter Pattern

Let’s look at the method signature again!

Generic Class-as-a-Parameter Pattern

The result in the main function is an improvement, since I am used to calling an infix function at the List. But we have that ugly class-as-a-parameter pattern again.

crewCrewCrew.printAnimalResultsExtensionFiltered(Sloth::class.java, Mammal::knownSpeciesCount)

Reified Generics-as-a-Parameter to the rescue!

Admittedly, I could work on my naming conventions, but we have written the same action in 5 different ways, and to me, this is what feels most natural to me. Again, we moved our class-as-a-parameter in to the <> next to our function.

crewCrewCrew.printAnimalResultsExtensionFiltered<Sloth>(Mammal::knownSpeciesCount)

I hope this post has proven revealing to how power generics in Kotlin can really be! You can follow along with exploration in Kotlin Generics by the week.

Navigate Generics in Kotlin articles here:

Kotlin Thursdays

Kotlin is a statically-typed language that runs on the JVM. Developed by a small JetBrains team in St. Petersburg, Kotlin is one of the hottest upcoming languages being used around the world. We’re here to grow together as an open-source community and to learn collaboratively!

mvndy

Written by

mvndy

software engineer and crocheting enthusiast

Kotlin Thursdays

Kotlin is a statically-typed language that runs on the JVM. Developed by a small JetBrains team in St. Petersburg, Kotlin is one of the hottest upcoming languages being used around the world. We’re here to grow together as an open-source community and to learn collaboratively!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade