Inline Function — When to use?
Tags: kotlin, android, androiddev
Published: 2024-04-29 13:54:26

In this article, we will investigate the Kotlin inline function in detail and come to a conclusion on when and why to use the inline function.

## What are inline functions?

To make the function inline, we will add the `inline` keyword before `fun` to convert normal function to inline function

```Kotlin
inline fun calculateTime() {
    println("Calculate")
}

fun main() {
    println("Start")
    calculateTime()
    println("End")
}
```

Decompiled:

```Java
public void main() {
   System.out.println("Start");
   System.out.println("Calculate");
   System.out.println("End");
}
```

As we can see complete body of inline function gets inserted at function call site when decompiled.

> **Inline** function are functions whose body gets copied to the calling place

**Advantage of Inline function:** No function call overhead — Faster program execution.

## Why not make every function inline?

Making Every function inline eventually grow the code as same code will repeat everywhere.

Some will say, if function body is small use inline otherwise not. This is correct upto some extent.

But when we inline a normal function with normal parameters, compiler will give us the below warning

`Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types`

So this means expected impact of inlining on performance is negligible as most probably compiler will do it if required.

## When do we inline the function?

We generally prefer to inline a function when function take functional type parameters (lambdas)

Let’s dive into the reason for this and how inlining actually help us in this case

In normal case:

```Kotlin
fun calculateTime(block: ()->Unit): Long {
    val initialTime = System.currentTimeMillis()
    block.invoke()
    return System.currentTimeMillis() - initialTime
}

fun main() {
    val time = calculateTime {
        println("Hello")
    }
    println(time)
}
```

Decompiled:

```Java
public long calculateTime(Function0 block) {
  long initialTime = System.currentTimeMillis();
  block.invoke();
  return System.currentTimeMillis() - initialTime;
}

public void main() {
  long time = calculateTime(
     new Function() {
        @Override
        public void invoke() {
          System.out.print("Hello");
        }
      }
    );
  System.out.println(time);
}
```
```Kotlin
public interface Function0<out R> : Function<R> {
    public operator fun invoke(): R
}
```

In Kotlin, function types (lambdas) are converted to object of anonymous/regular classes(`Function0`) that extend the interface `Function`

**Problem?** — If we call this function (`calculateTime`) 100 times, 100 object of `Function` class will be created and garbage collected. This affects performance.

**Solution?** — Use inline for preventing object creation

```Kotlin
inline fun calculateTime(block: ()->Unit): Long {
    val initialTime = System.currentTimeMillis()
    block.invoke()
    return System.currentTimeMillis() - initialTime
}

fun main() {
    val time = calculateTime {
        println("Hello")
    }
    println(time)
}
```

Decompiled:

```Java
public void main() {
  long initialTime = System.currentTimeMillis();
  System.out.println("Hello");
  long time = System.currentTimeMillis() - initialTime;
  System.out.println(time);
}
```

So, the functions that take other functions as arguments are faster when they are inlined (since no `Function` objects are created).

We should use inline function when we have functional type parameter with small function body.

### noinline

What if we have multiple functional type parameter in the inline function and we do not want to inline all the parameters, we can use `noinline` keyword.

```Kotlin
fun main() {
    val time = calculateTime({
        println("Hellow")
    }, {
        println("World")
    })
    println(time)
}

inline fun calculateTime(block1: () -> Unit, noinline block2: () -> Unit): Long {
    val initialTime = System.currentTimeMillis()
    block1.invoke()
    block2.invoke()
    return System.currentTimeMillis() - initialTime
}
```

Decompiled code:

```Java
public static final void main() {
  long initialTime = System.currentTimeMillis();
  System.out.println("Hello");
  Function block = new Function() {
        @Override
        public void invoke() {
          System.out.print("World");
        }
      }
    );
  block.invoke();
  long time = System.currentTimeMillis() - initialTime;
  System.out.println(time);
}
```

### crossinline

`crossinline` keyword is used to avoid non-local returns.

Let’s understand with example

```Kotlin
inline fun calculateTime(block: () -> Unit): Long {
    val initialTime = System.currentTimeMillis()
    block.invoke()
    return System.currentTimeMillis() - initialTime
}

fun main() {
    val time = calculateTime {
        println("Hello")
        return
    }
    println(time)
}
```

Decompiled:

```Java
public static final void main() {
   long initialTime = System.currentTimeMillis();
   System.out.println("Hello");
}
```

Here we can see that after return, no other statement is written (calculating and printing final time). This is non-local return. To avoid this issue, we can mark the lambda as `crossinline`.

```Kotlin
inline fun calculateTime(crossinline block: () -> Unit): Long {
    val initialTime = System.currentTimeMillis()
    block.invoke()
    return System.currentTimeMillis() - initialTime
}

fun main() {
    val time = calculateTime {
        println("Hello")
        return // This will give compile time error
    }
    println(time)
}
```

When mark lambda parameter as `crossinline`, if we add return statement, compiler will give the error (`‘return’ is not allowed here`).

### Use inline for reified type parameters

What if we want to work with class type directly in Kotlin generics?

```Kotlin
fun <T> doSomething(value: T) {
   println("Value: $value") // OK
   println("Type: ${T::class.simpleName}") // Error
}

fun main() {
   doSomething("something")
}
```

In the above example we get the error

`Cannot use 'T' as reified type parameter. Use a class instead`

We cannot work with the type directly, because the type argument gets erased at runtime when we pass to the function. So, we cannot possibly know exactly which type we are handling.

**Solution?** — Use an inline function along with the reified type parameter.

```Kotlin
inline fun <reified T> doSomething(value: T) {
   println("Value: $value") // OK
   println("Type: ${T::class.simpleName}") // OK
}

fun main() {
   doSomething("something")
}
```

In the above example actual type argument will be copied in place of T. So, `T::class.simpleName` becomes `String::class.simpleName`.

The reified keyword can only be used with inline functions.

Source Code: [Github](https://github.com/khushpanchal/HappyCoding/blob/master/app/src/main/java/com/khush/happycoding/kotlin/InlineFunction.kt)

Contact Me:
[LinkedIn](https://www.linkedin.com/in/khush-panchal-241098170/), [Twitter](https://twitter.com/KhushPanchal15)

Happy Coding ✌️