1. Overview

In Kotlin 1.3+, we have an experimental new type of class, called inline class. In this tutorial, we’ll focus on the usage of inline classes and also some of their limitations.

2. Setup

As we mentioned before, inline classes are an experimental feature of Kotlin. As a consequence, the compiler will throw a warning indicating the experimental status of the feature.

To avoid this warning, we can add the following Maven compiler option to our configuration:

<configuration>
    <args>
        <arg>-XXLanguage:+InlineClasses</arg> 
    </args>
</configuration>

3. What Are Inline Classes?

Inline classes provide us with a way to wrap a type, thus adding functionality and creating a new type by itself.

As opposed to regular (non-inlined) wrappers, they will benefit from improved performance. This happens because the data is inlined into its usages, and object instantiation is skipped in the resulting compiled code.

Let’s see an example of an inline class called InlinedCircleRadius with a property of type Double representing the radius:

val circleRadius = InlinedCircleRadius(5.5)

For the JVM, our code is actually just:

val circleRadius = 5.5

Notice how our InlinedCircleRadius is not instantiated in the compiled code because the underlying value is inlined, relieving us from the performance penalties associated with instantiation.

3.1. Usage Example

Now that we know what inline classes are, we’ll discuss their usage.

A single property initialized in the primary constructor is the basic requirement of an inline class. The single property will represent the class instance at runtime.

Therefore, in order to have a correct definition, we can use a single line of code:

inline class InlineDoubleWrapper(val doubleValue : Double)

We defined InlineDoubleWrapper as a simple wrapper over a Double object and applied the inline keyword to it. Finally, we can now use this class in our code with no additional changes:

@Test
fun whenInclineClassIsUsed_ThenPropertyIsReadCorrectly() {
    val piDoubleValue = InlineDoubleWrapper(3.14)
    assertEquals(3.14, piDoubleValue.doubleValue)
}

4. Class Members

Up until now, we used inline classes just like simple wrappers. But they are so much more than that. They also allow us to define properties and functions just like regular classes. This next example defines a property representing the diameter and a function to return the area of the circle:

inline class CircleRadius(private val circleRadius : Double) {
    val diameterOfCircle get() = 2 * circleRadius
    fun areaOfCircle = 3.14 * circleRadius * circleRadius
}

We’ll now create a test for our diameterOfCircle property. It will instantiate our CircleRadius inline class and then call the property:

@Test
fun givenRadius_ThenDiameterIsCorrectlyCalculated() {
    val radius = CircleRadius(5.0)
    assertEquals(10.0, radius.diameterOfCircle)
}

And here’s a simple test for the areaOfCircle function:

@Test
fun givenRadius_ThenAreaIsCorrectlyCalculated() {
    val radius = CircleRadius(5.0)
    assertEquals(78.5, radius.areaOfCircle())
}

However, there are some limitations on what we can and can’t define inside our inline classes. While properties and functions are allowed, we have to mention that init blocks, inner classes, and backing fields are not.

5. Inheritance

It is important to mention that inline classes can inherit only from interfaces, and since we can’t have subclasses, inline classes are also effectively final.

Given an interface Drawable with a method draw(), we’ll implement this method in our CircleRadius class:

interface Drawable {
    fun draw()
}

inline class CircleRadius(private val circleRadius : Double) : Drawable {
    val diameterOfCircle get() = 2 * circleRadius
    fun areaOfCircle() = 3.14 * circleRadius * circleRadius

    override fun draw() {
        println("Draw my circle")
    }
}

6. Conclusions

In this quick article, we explored inline classes in Kotlin. In addition, we talked about inheritance and the definition of properties and functions.

As usual, all of these examples and snippets can be found over on GitHub.

2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Vitali Plagov
8 months ago

Thanks for the article! Although, I think it doesn’t describe the benefit and use cases of using inline classes. A very good example of considering using an inline class is when you have a function that takes in two parameters (or more) of the same type, for example: fun doSomeThingWithDates(year: Int, month: Int) With help of inline classes, it’s possible to add extra type-safety here. For example: inline class Year (val value: Int) inline class Month (val value: Int) fun doSomeThingWithDates(Year(2021), Month(2)) This way the caller of the function won’t mix up with the order of the arguments to pass… Read more »

Loredana Crusoveanu
Loredana Crusoveanu
4 months ago
Reply to  Vitali Plagov

Thanks for the addition, Vitali.

Comments are closed on this article!