# A Practical Guide to Kotlin's inline Modifier

I fell in love with Kotlin as soon as I switched to it from Java about 4 years ago. And although I was writing Kotlin code on a regular basis ever since, I didn't start using some of its more advanced features until quite recently.

I wish I had started playing around with the more idiomatic ways to write Kotlin code much sooner since it improves the quality of the code and makes writing code much more enjoyable. I agree that you can easily get by without ever using the less-known Kotlin features, however, in the hands of more dedicated software enthusiasts, those features can help improve the code dramatically.

In this article, we will go through one of those features - the `inline` modifier. And yes, it means we will also take a close look at the modifiers that are closely linked with the inline functions - `noinline`, `crossinline`, and `reified`.

## Contents


```
1. Inline modifier
   1.1. Inline functions
   1.2. Inline properties
   1.3. Inline classes
2. Noinline modifier
3. Crossinline modifier
   3.1. Understanding non-local returns
   3.2. The problem and the crossinline solution
4. Reified modifier
``` 


## 1. Inline modifier

### 1.1. Inline functions

In Kotlin, you cannot throw a stone without hitting a *higher-order function*. In layman's terms, those are functions that either take functions as parameters or return a function. This makes Kotlin a very flexible language and allows for intuitive functional programming as well as easy creation of DSLs among many other things.

But as with most amazing things in life, there is a catch. Using many higher-order functions can cause a significant performance impact during runtime since every function *compiles to an object that captures a closure*. A closure is a fancy way of describing the variables that this function accesses but are declared outside of its scope. Therefore, without a clever solution from the folk at JetBrains, Kotlin might as well have been called the runtime overhead language.

That solution is the `inline` modifier.

When a function is marked with `inline` the compiler *doesn't create new objects but rather inserts the given code where an inline function is called*.

Let's take a look at a simple example:

```kotlin
fun main() {
    doubleAction(
        { println("Hello") },
        { println("World!") }
    )
}

fun doubleAction(
    action1: () -> Unit,
    action2: () -> Unit
) {
    action1()
    action2()
}
``` 

If we decompile the bytecode of this block back to Java and look at the `main()` function, we will see:

```java
public static final void main() {
    doubleAction((Function0)null.INSTANCE, (Function0)null.INSTANCE);
}
```

To be honest, at first glance this looks like someone is looking for a creative way to get a `NullPointerException` but let's not concern ourselves with the ways of Kotlin bytecode decompiler.

What we should note here is that our `main` is calling the `doubleAction` function and our two lambdas are now instances of `Function0` object.

Now, let's see what happens if we put the `inline` modifier in front of the `doubleAction` function:

```kotlin
inline fun doubleAction(
    action1: () -> Unit,
    action2: () -> Unit
) {
    action1()
    action2()
}
```

Just by doing that, after compiling this code into bytecode and decompiling back to Java (and a little bit of cleanup to illustrate the point) the body of our `main` function reads:

```java
public static final void main() {
    String var1 = "Hello";
    System.out.println(var1);
    var1 = "World!";
    System.out.println(var1);
}
```

Now that is much more efficient! The compiler even reuses the `String` variable.

I hope that this example nicely illustrates the benefits of using the `inline` modifier for higher-order functions. *It will inline the function itself as well as lambdas that are passed as arguments.*

**In summary**

The `inline` modifier provides a noticeable performance boost if you write a lot of higher-order functions, especially in a big codebase, so use it!

Also, for those of you writing Android UI with Jetpack Compose, `inline` will become your friend pretty fast.

However, a word of caution must be mentioned here. It is not recommended to `inline` *large functions*, since it can considerably bloat the generated code. Inlining, like everything else really, is good in moderation.

It works great with short functions, especially when using loops and working with collections.

For example, in Kotlin standard library the scope functions (`let`, `apply`, `also`, `run`, and `with`) are marked with `inline`, as well as extension functions that work with `Iterable` collections, such as `map`, `forEach`, `fold` and many others.

### 1.2. Inline properties

Marking higher-order functions is not the only use of the `inline` modifier, however. One of the less-known features of the Kotlin language are **inline properties**.

Let's take a look at the following example:

```kotlin
var complexProperty: Int
    get() {
        val x = 2
        val y = 4
        return x + y
    }
    set(value) {
        val adjustedValue = value + 10
        println("Setting adjusted value $adjustedValue")
    }

fun main() {
    complexProperty = 4
    val calculatedProperty = complexProperty
    println("The property is $calculatedProperty")
}
```

> Take note that these are not regular getter and setter methods that read/write a backing field. We will discuss it in a bit.
> 

The accessors of Kotlin properties are compiled to regular methods, which then are used throughout the code. So our example after the bytecode magic will read:

```java
public static final void main() {
    setComplexProperty(4);
    int calculatedProperty = getComplexProperty();
    String var1 = "The property is " + calculatedProperty;
    System.out.println(var1);
}
```

If you have paid attention until now, you probably know what we are about to do.

Yes, we can mark the property as `inline`, which will make the accessors of the property work like regular inline functions, **even though they are not higher-order**. 

So after marking our property with `inline`:

```kotlin
inline var complexProperty: Int
    get() {
        val x = 2
        val y = 4
        return x + y
    }
    set(value) {
        val adjustedValue = value + 10
        println("Setting adjusted value $adjustedValue")
    }
```

We will get:

```java
public static final void main() {
    // Setter
    int value$iv = 4;
    int adjustedValue$iv = value$iv + 10;
    String var3 = "Setting adjusted value " + adjustedValue$iv;
    System.out.println(var3);

	// Getter
    int x$iv = 2;
    int y$iv = 4;
    int calculatedProperty = x$iv + y$iv;
    String var6 = "The property is " + calculatedProperty;
    System.out.println(var6);
}
```

Exactly what we would expect from an inlined function.

We can also mark individual accessors as `inline`:

```kotlin
var complexProperty: Int
    inline get() {
        ...
    }
    set(value) {
		...
    }
```

Or:

```kotlin
var complexProperty: Int
    get() {
        ...
    }
    inline set(value) {
	    ...
    }
```

And of course, have read-only properties:

```kotlin
inline val complexProperty: Int
    get() {
       ...
    }
```

**Inline property restriction**

There is a reason why we didn't use a property with regular getter and setter in our example. That reason is that the `inline` modifier is only allowed for accessors that don't have a backing field.

> Backing field is an identifier **field** that doesn't allow us to go into an infinite loop when setting a property.
> 

### 1.3. Inline classes

Inline classes are another less-known feature of Kotlin that became stable in Kotlin 1.5.0, and even though they are not using the `inline` modifier directly in their stable version, they did during the experimental phase in earlier Koltin versions, and their functionality is the same as we have seen with previous inlined examples.

Inline classes act as a wrapper around a type *to improve readability and decrease the probability of runtime bugs*. The regular wrapper class would have a noticeable performance hit during runtime due to additional heap allocations. The inline classes don't, while keeping all the benefits.

Below is a snippet of code where we should consider using a wrapper:

```kotlin
fun main() {
    login("qwerty", "email@qwerty.com")
}

fun login(email: String, password: String) {
    println("Please don't mix up my parameters")
}
```
As you can see, this code will compile nicely but would break during runtime (if it had some login logic of course).

This is where inline classes shine.

We can re-write the following code as follows:

```kotlin
fun main() {
    login(Email("email@qwerty.com"), Password("qwerty"))
}

fun login(email: Email, password: Password) {
    println("Please don't mix up my parameters")
}

@JvmInline
value class Email(val email: String)

@JvmInline
value class Password(val password: String)
```

Before Kotlin 1.5.0 we would write:

```kotlin
inline class Email(val email: String)
```

But this syntax is deprecated now and will throw a warning.

When using this approach it will be much harder to mix up our types, and during runtime no new objects will be created.

Moreover, the inline classes can have `init` blocks, functions, and properties (with the same restrictions as the inline properties):

```kotlin
@JvmInline
value class Email(val email: String) {
    init {
        require(email.isValidEmail())
    }
}

@JvmInline
value class Password(val password: String) {
    val isSecure: Boolean
        get() = password.contains('!')
}
```

If you want some more practical inspiration on the inline classes, you can take a look at this [article](https://jakewharton.com/inline-classes-make-great-database-ids/) by Jake Wharton.

## 2. Noinline modifier

At this point, we hopefully have a decent understanding of how inlining works, therefore let's take a look at the modifiers that work in the context of inline functions.

The first of those modifiers is quite straightforward.

If we don't want to (or can't) inline a lambda that is passed as a parameter to an inline function, we can mark it as `noinline`.

Here are a couple examples where we might wan't to mark our lambda parameter as `noinline`:

```kotlin
inline fun doubleAction(
    action1: () -> Unit,
    action2: () -> Unit
) {
    action1()

    // the following two cases won't compile
    // we cannot assign an inline lambda to a variable
    val x = action2
    // we cannot pass an inline lambda to a non-inline function
    singleAction(action2)
}

/**
 * For some reason this function is not inlined.
 * It might be too large or comes from external
 * library that we don't have any control over
 */
fun singleAction(action: () -> Unit) {
    action()
}
```

This can easily be fixed by telling the compiler that we don't want to inline the `action2` lambda. All we need to do is mark it as `noinline`:

```kotlin
inline fun doubleAction(
    action1: () -> Unit,
    noinline action2: () -> Unit
) {
	...
}
```
Now the above code will compile and work nicely.

Needless to say that if you have and inline function with one lambda as a parameter, in most cases it wouldn't make sense to mark in as `noinline`, and the IDE will promptly give you warning in that case.

However, it depends on what we do with that lambda parameter.

Here is an example from the Kotlin Coroutines library:

```kotlin
public suspend inline operator fun <T> CoroutineDispatcher.invoke(
    noinline block: suspend CoroutineScope.() -> T
): T = withContext(this, block)
```

The `withContext` is a regular function and we cannot pass an inlined lambda to it (more on why in the `crossinline` section):

```kotlin
public suspend fun <T> withContext(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T
```

But we can still inline the `withContext` function where we call `invoke` on our `CoroutineScope` so this is another good example of `noinline` modifier in practice.

## 3. Crossinline modifier

To understand why we might need the `crossinline` modifier, we must first have a good understanding of **non-local returns** in Kotlin.

If you are familiar with this concept, feel free to skip the next part.

### 3.1. Understanding non-local returns

There are only 3 places in Kotlin where we can use a normal `return` without any additional labels:

1. Named functions
```kotlin
fun regularNamed(isSleepy: Boolean) {
       if (isSleepy) {
           return
       }
       // do stuff
}
```
2. Anonymous functions (do not confuse them with lambdas)
```
fun printEven(listOfInts: List<Int>) {
       listOfInts.forEach(fun(x: Int) {
           if (x % 2 == 0) {
               println(x)
           } else {
               /** 
               * This will return at the anonymous fun
               * and continue forEach iteration.
               * Lambda would have returned at printEven
               * since forEach is inlined.
               */
               return
           }
       })
}
```
> In most cases, we wouldn't use anonymous functions. However, keep in mind that anonymous functions allow us to specify an explicit return type, while lambdas don't.

3. Inline functions
```
fun weAllFloat(list: List<Any>) {
       list.forEach { 
           if (it !is Float) {
               /** 
               * Once again, forEach is inline
               * and will return at weAllFloat.
               * If we would like to continue looping,
               * we should use a local return@forEach
               */
               return
           } else {
               it.float() 🎈
           }
       }
}
```

These are **non-local returns**.

To use a `return` inside a lambda, we must *use either a default or a custom label*:

```kotlin
// not the cleanest code, but illustrates our point
val hasString = lambda@{
    list.forEach { 
        if (it is String) {
            return@lambda true
        }
    }
    return@lambda false
}
print(hasString())
```

These are **local returns**.

The reason we can use a non-local `return` inside an inlined lambda is that it will just return from the enclosing function, where the code will be inlined.

### 3.2. The problem and the crossinline solution

But there is a problem that can arise with the inlined lambdas and their non-local returns:

```kotlin
fun main() {
	inlineFunction {
		return // this is fine, no compile error here
    }
}

inline fun inlineFunction(inlineLambda: () -> Unit) {
    randomFunction {
        inlineLambda() // compile error
    }
}

fun randomFunction(nonInlineLambda: () -> Unit) {
    nonInlineLambda()
}
```

The `nonInlineLambda` is a regular lambda and we cannot use a non-local return inside a regular lambda. Inline lambdas, however, allow non-local returns, and in this case, it would be inlined inside a regular lambda.

The compiler doesn't like that idea and since it cannot guarantee that we won't try to pass a non-local return inside an inline lambda to a regular function, it just doesn't allow passing inline lambdas to regular functions altogether.

We've had a very similar example in the `noinline` section, where we passed an inline lambda to the regular `withContext` function. In that case, the problem was solved by not inlining the lambda at all, which is one way to do it.

The other solution is the `crossinline` modifier. By marking a lambda parameter with `crossinline` we *prohibit using the non-local return inside that inline lambda*, and therefore can safely pass it to a regular function.

That said, let's fix our code:

```kotlin
fun main() {
    inlineFunction {
        // the non-local return won't compile here anymore
        return@inlineFunction
    }
}

inline fun inlineFunction(crossinline inlineLambda: () -> Unit) {
    randomFunction {
        inlineLambda() // now this is perfectly fine
    }
}

fun randomFunction(nonInlineLambda: () -> Unit) {
    nonInlineLambda()
}
```

Now we can have all the benefits of our `inlineLambda` and the compiler won't have to worry about non-local returns.

A good example of `crossinline` in the Kotlin standard library is the `sortBy` function:
```
public inline fun <T, R : Comparable<R>> MutableList<T>.sortBy(
    crossinline selector: (T) -> R?
): Unit
```
It passes the `selector` down to a regular function, but still inlines the comparator logic. 

## 4. Reified modifier

Finally, we got to the final modifier that we will discuss today. This is probably my favorite one since it allows for some clever solutions.

Let's take a look at a simple example:

```kotlin
fun main() {
    val json = "{ ... }"
    val user = json.asObjectFromJson(User::class.java)
}

fun <T> String.asObjectFromJson(classType: Class<T>): T? {
    // validate json
    // do some deserialization
    // return an instance of classType
}
```

In a regular function, type `T` is *only available during compile time and is erased at runtime*. Therefore normally, we cannot infer the class of `T` at runtime and have to pass a `Class` as a parameter.

The `reified` modifier fixes this inconvenience. However, keep in mind that we can only use `reified` in the inlined functions.

Here is how we can improve our code using the `reified` modifier:

```kotlin
fun main() {
    val json = "{ ... }"
    // the call looks prettier as well
    val user = json.asObjectFromJson<User>()
}

inline fun <reified T> String.asObjectFromJson(): T? {
    // validate json
    // do some deserialization
    // we can access the class of T during runtime now!
    return T::class.java.newInstance()
}
```

By marking our generic `T` as `reified` we can use it inside the function as if it was a normal class.

The `inline` function makes this possible without using reflection, however, if you need to use it, reflection also becomes available for the `reified` types as well as operators like `is` and `as` that work with classes.

One of the most common examples of `reified` in the Kotlin standard library is the `Iterable` extension function `filterIsInstance`:

```
list.filterIsInstance<String>()
```

## Conclusion

When switching from Java to Kotlin, it can be very tempting to continue writing Java code, only using Kotlin. Kotlin will not stop you from doing that.

However, Kotlin offers so much more and any Kotlin user would be doing themselves a huge disservice by missing out on a huge variety of features that Kotlin provides.

Today we have looked at some of those features, and, hopefully, this information will help you write better idiomatic Kotlin code.

See you next time.

*To growing and sharing,*

*Your friend,*

*Max*
