Matt's Tidbits #66 - The magic of Kotlin's "reified" keyword
Tags: mattstidbits, kotlin, testing, tidbittuesday
Published: 2020-04-28 13:21:37

[Last week I called for proper support of JUnit 5 by the Android Gradle Plugin.](https://medium.com/@matthew.b.groves/matts-tidbits-65-it-s-time-for-proper-support-for-junit-5-e2ded84bd929) This time, I want to make sure you know about Kotlin's `reified` keyword and just how awesome it is!

Recently, I was writing some unit tests for some generic functions, and needed some mockable types I could work with.

So, I created a type like this:
```kotlin
typealias TestObjectID = String

private class TestObject {
  val id: TestObjectID
  
  fun singleCommand(): Single<String> = Single.never()
  fun maybeCommand(): Maybe<String> = Maybe.never()
  fun completableCommand(): Completable = Completable.never()
}
```

This let me mock out the various command methods as desired. However, what I discovered (somewhat by accident), is that it was easy to introduce errors from copying/pasting code between tests, since this one object contained all of the various methods I was attempting to test - and if I had mocked the wrong one, it was a little bit confusing to figure out why the test wasn't working.

To make my tests less susceptible to this type of error, I instead split things up like this:
```kotlin
typealias TestObjectID = String

private interface TestObject {
  val id: TestObjectID
}
private interface SingleTestObject : TestObject {
  fun command(): Single<String> = Single.never()
}
private interface MaybeTestObject : TestObject {
  fun command(): Maybe<String> = Maybe.never()
}
...
```

When set up this way, the method for each object can be named the same (which is nice for readability), and I have to create a SingleTestObject to use the method that returns a Single, a MaybeTestObject to use the method that returns a Maybe, etc. - and I no longer have to worry about mixing up types accidentally.

I am a huge believer in modularized test code that is engineered just as well as the rest of your code. So, instead of each test constructing these different objects manually and mocking them, I like to create a series of helper methods that define various scenarios/common setups. This allows me to reuse that setup code across my tests, and furthermore if the tests need to change to reflect changes in the actual code, it minimizes the number of places I have to fix.

This new setup presented one problem when I wanted to supply a value for the `id` field of the `TestObject` interface. I wanted to be able to use a builder pattern, so I could easily configure multiple options in a single sequence. One option would have been to use Kotlin's `apply` block and a helper method that took an instance of a `TestObject`, like this:
```kotlin
private fun TestObject.setId(id: TestObjectID) {
  every { this@setId.id } returns id
}

val mockTestObject = createSingleMockTestObject().apply {
  setId("foo")
}
```

However, I had another idea that I liked even more that uses Kotlin's `inline`, `reified`, and `where` keywords:
```kotlin
private inline fun <reified T> T.withId(id: TestObjectID): T
    where T : TestObject {
  every { this@withId.id } returns id
  return this
}
```

Why does this work? The `reified` and `inline` keywords work together - you can only use reified types if the function is inline. The `reified` keyword allows this function to return the same type as what was passed in (such as `SingleTestObject` or `MaybeTestObject`, even though the operation is performed on the parent class' interface. The `where` keyword is what allows us to access the `id` field of `TestObject` - because this method is only available for objects of type `TestObject` - so you will not see the `withId` method appear as a suggestion for other types (such as `String`).

**Update:**
A friend a former coworker (@russhwolf) pointed out that the `where` statement above is not required.  You can achieve the same result by writing the method like this:
```kotlin
private inline fun <reified T: TestObject> T.withId(id: TestObjectID): T {
  every { this@withId.id } returns id
  return this
}
```

Now, I can use this method in a true builder pattern fashion, and thanks to these special keywords, it will do exactly what I want!
```kotlin
val mockTestObject = createSingleMockTestObject()
  .withId("foo")
  .withSingleValue(Single.just("bar"))
```

Notice how I can chain the calls together and call the `withSingleValue()` function, which only applies to `SingleTestObject` instances, even though the `withId()` function will operate on any `TestObject`!

I hope you learned something interesting and useful, and please share your stories about how you have used Kotlin's `reified` types in the comments below. And, please follow me on Medium if you're interested in being notified of future tidbits.

*This tidbit was discovered on April 13, 2020.*