Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

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.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE