# Noinline va crossinline. Can you clarify?

**URL:** <https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175>\
**Category:** Language Design\
**Created:** [January 5, 2023, 3:50pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175 "2023-01-05T15:50:17Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![alexander.kot](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@alexander.kot](https://discuss.kotlinlang.org/u/alexander.kot)\
**Post date:** [January 5, 2023, 3:50pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/1 "2023-01-05T15:50:17Z")

</div>

Hello! I am trying to understand a difference between noinline and crossnline keywords in use.

I know that noinline destroys the optimization given by the online keyword.  
I noticed that I can use crossinline everywhere I use noinline.

What can you say about the crossinline in terms of optimization?

Thank you

---

<div class="post-metadata">

**Author:** ![arocnies](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/arocnies/32/5143_2.png) [@arocnies](https://discuss.kotlinlang.org/u/arocnies)\
**Post date:** [January 5, 2023, 4:45pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/2 "2023-01-05T16:45:53Z")

</div>

Not a full answer but I just wanted to highlight that inlining is often more about specialized returns and reified generics than performance.

I’d be hesitant to set any function as inline for performance unless there’s a clear and evident need.

I’m sure someone else will have a better full answer for crossinline 🙂

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [January 5, 2023, 6:13pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/3 "2023-01-05T18:13:52Z")

</div>

You can read my comment here: [Coroutines and crossinline - #2 by broot](https://discuss.kotlinlang.org/t/coroutines-and-crossinline/25737/2) It was about suspending, but I provided examples on inline, crossinline and noinline.

---

<div class="post-metadata">

**Author:** ![alexander.kot](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@alexander.kot](https://discuss.kotlinlang.org/u/alexander.kot)\
**Post date:** [January 7, 2023, 11:50am UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/4 "2023-01-07T11:50:12Z")

</div>

Are you sure this is not about performance?  
There are many articles about the online keyword, which say that, inline reduce runtime overhead (lambda turns to a separate object and this is bad for the performance)  
This one, for instance:

> **[Kotlin’s Noinline & Crossline, once for all](https://ncorti.com/blog/noinline-and-crossline-once-for-all)**
>
> Explaining the Kotlin’s noinline and crossinline keywords, with a simple example, once for all.

---

<div class="post-metadata">

**Author:** ![alexander.kot](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@alexander.kot](https://discuss.kotlinlang.org/u/alexander.kot)\
**Post date:** [January 7, 2023, 11:59am UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/5 "2023-01-07T11:59:59Z")

</div>

Thanks for you answer in that tread.

if I understand correctly:

- noinline removes lambda inlining completely.

- crossinline works in “automatic mode” - if this word is written, then it tries to leave inline optimization, if possible. If this is not possible, then it will work like noinline.

Right?

---

<div class="post-metadata">

**Author:** ![Tassilo](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/tassilo/32/8548_2.png) [@Tassilo](https://discuss.kotlinlang.org/u/Tassilo)\
**Post date:** [January 7, 2023, 12:19pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/6 "2023-01-07T12:19:23Z")

</div>

From my understanding, marking something as `noinline` will completely remove the inlininig, and create a separate function object for the lambda, decreasing the performance.

`crossinline` will still inline the lambda, but simply disallow returns.

Take this example:

```kotlin
inline fun test(block: () -> Unit) {
  print("Start of test")
  block()
  print("End of test")
}

fun main() {
  print("Start of main")
  test {
    print("Test!")
  }
  print("End of main")
}

```

As we did not declare the `block` parameter in the `test` function as `crossinline`, we can simply put a `return@main` after the `print("Test!")` statement, to return from the `main` function. The generated code will then look like this:

```java
public static final void main() {
    String var0 = "Start of main";
    System.out.print(var0);
    int $i$f$test = false;
    String var1 = "Start of test";
    System.out.print(var1);
    int var2 = false;
    String var3 = "Test!";
    System.out.print(var3);
}

```

As you can see, we don’t even reach the statements after the return. If we instead mark the `block` parameter as `crossinline`, we can no-longer `return` the main function from inside the lambda. The compiler will tell you, that `return@main` is not allowed there. You can merely `return@test`, to jump out of the lambda and back to the normal function again. This time, all the remaining print statements will still be invoked. The generated code for `crossinline` will look like this:

```java
public static final void main() {
    String var0 = "Start of main";
    System.out.print(var0);
    int $i$f$test = false;
    String var1 = "Start of test";
    System.out.print(var1);
    int var2 = false;
    String var3 = "Test!";
    System.out.print(var3);
    var1 = "End of test";
    System.out.print(var1);
    var0 = "End of main";
    System.out.print(var0);
}

```

TL;DR: `crossinline` will still fully inline the lambda, but simply prevent returns to the calling function from inside the lambda. So in terms of optimization, they work pretty much the same.

Or in other words, `crossinline` will give the optimization of inlining, without allowing the lambda to return the outer function directly.

If you want to mess around with the code the Kotlin generates yourself, you can simply create a Kotlin file in a project, then go to _Tools → Kotlin → Show Kotlin Bytecode_ and then click _Decompile_.

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [January 7, 2023, 2:12pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/7 "2023-01-07T14:12:49Z")

</div>

> [@alexander.kot](#):
>
> crossinline works in “automatic mode” - if this word is written, then it tries to leave inline optimization, if possible. If this is not possible, then it will work like noinline.

Yes, I think we can say that.

`inline` means it is guaranteed the code can be fully inlined. Such guarantee is a requrement in order to use `reified`, non-local returns, etc. `noinline` means we don’t want to inline the lambda at all. `crossinline` means we would like to inline if possible, but we can’t **guarantee** we can do it or we can only inline it partially. For this reason we have to disable additional features which require full inlining, even if in some cases it would be possible to use them. `crossinline` could happen in situations like:

- We can only inline partially, so we can’t inline it directly to the body of the caller, but we would still like to inline it in another place, for example in lambdas created inside the higher-order function (see my linked example).
- There is a runtime condition and depending on it we either invoke the lambda directly or pass it somewhere else.
- For now it is possible to fully inline, but we expect in the future it may be not possible, so we use `crossinline` already to avoid making backward-incompatible change at a later time.

> [@Tassilo](#):
>
> Or in other words, `crossinline` will give the optimization of inlining, without allowing the lambda to return the outer function directly.

You don’t see a difference between `inline` and `crossinline`, because your example is too simple. You didn’t try to pass `block` anywhere, which is the case when all 3 keywords start to do different things.

---

<div class="post-metadata">

**Author:** ![Tassilo](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/tassilo/32/8548_2.png) [@Tassilo](https://discuss.kotlinlang.org/u/Tassilo)\
**Post date:** [January 7, 2023, 2:45pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/8 "2023-01-07T14:45:15Z")

</div>

> [@broot](#):
>
> You don’t see a difference between `inline` and `crossinline`, because your example is too simple. You didn’t try to pass `block` anywhere, which is the case when all 3 keywords start to do different things.

I see a difference between `inline` and `crossinline`, but both work _roughly_ the same, in terms of them inlining the code to _some_ site.

If you want to _pass_ an inlined or cross-inlined parameter anywhere, e.g. into a variable, or as a lambda parameter to a non-inline function, it will fail, because that requires the lambda to be an object and not inlined. So you **have** to declare the _block_ as `noinline` or remove `inline` from the function in that case. Take the following example:

```kotlin
fun someFunction(block: () -> Unit) {
  // Do something, this is not inlined.
}

inline fun test(crossinline block: () -> Unit) {
  // This will fail, even for crossinline, because block is still inlined,
  // but not an object itself.
  val x = block

  // This will also fail, because block is still inlined and cannot be passed as an object.
  // someFunction however requires its lambda parameter to be an object, because it is not inlined.
  someFunction(block)

  // This WILL work. And this is where the difference between crossinline and normal inline will show.
  // We don't pass block as a lambda parameter, but instead create a new lambda here.
  // While creating the lambda, we inline the contents of block into this.
  // The created lambda is now a new object, so someFunction can store it in a variable,
  // and also pass it to other no-inline functions.
  // Since we create a new lambda here, which has no guarantee about when it will be called,
  // let alone if it will even be called at all, we HAVE TO declare block as crossinline,
  // since whatever we write into block, CANNOT return to the outer function.
  someFunction {
    block()
  }
}

```

Let’s take the last example and let a function call `test`.

```kotlin
fun main() = test { println("Hello World!") }

```

`test` itself is still an inline function, despite its lambda parameter being crossinlined. The compiler will now generate the following:

```java
public static final void main() {
  // The compiler will still inline the function test, as its an inlined function,
  // and thus directly call someFunction.
  // Since someFunction is NOT inline, the lambda HAS to be created as a separate object.
  someFunction(new MainKt$x$$inlined$test$1());
}

public final class MainKt$x$$inlined$test$1 extends Lambda implements Function0 {
  // ...
  public final void invoke() {
    int var1 = false;
    String var2 = "Hello World!";
    System.out.println(var2);
  }
}

```

As you can see, in this case `crossinline` will STILL inline the contents we pass in the lambda, in this case, by inlining them into the lambda we create. Due to this, we cannot allow returns to the outer function, since the control flow doesn’t _necessarily_ go back to the call-site.

From the [documentation](https://kotlinlang.org/docs/inline-functions.html):

> Note that some inline functions may call the lambdas passed to them as parameters not directly from the function body, but from another execution context, such as a local object or a nested function. In such cases, non-local control flow is also not allowed in the lambdas. To indicate that the lambda parameter of the inline function cannot use non-local returns, mark the lambda parameter with the `crossinline` modifier.

That being said, both lambdas with and without being marked as `crossinline` will generally get the optimizations of inlining, but serve different purposes. You mark lambas as `crossinline` if you store the lambda in a variable, pass it to another non-inlined function, or simply don’t want outer returns from the lambda.

If we would mark the `block` parameter of the `test` function as `noinline`, then we could directly pass the lambda to `otherFunction`. If we still create a separate lambda, then two lambda objects will be created, one containing the _“Hello World!”_ and the other merely being a wrapper, that calls the first lambda.

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [January 7, 2023, 3:24pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/9 "2023-01-07T15:24:57Z")

</div>

Yes, exactly, this is the case which I believe shows the difference between all 3 keywords the best. If we try to create a lambda that invokes `block()` and then pass this lambda somewhere:

```kotlin
inline fun foo(block: () -> Unit) {
    bar {
        // do something
        block()
        // do something
    }
}

fun bar(block: () -> Unit) { ... }

```

Then:

- inline (no modifier) - doesn’t compile as `inline` requires the `block` to be inlined together with the code of `foo`.
- crossinline - allows to inline `block` into the contents of the lambda, so only one lambda object is created. This is why the name “crossinline” - it doesn’t inline directly, but it inlines in further places (my own interpretation).
- noinline - disallows inlining `block` into lambda, so we require 2 lambda objects here (although one of them is re-used between call sites).

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [January 7, 2023, 6:50pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/10 "2023-01-07T18:50:19Z")

</div>

> [@alexander.kot](#):
>
> Are you sure this is not about performance?  
> There are many articles about the online keyword, which say that, inline reduce runtime overhead (lambda turns to a separate object and this is bad for the performance)

Performance is always a complicated topic in JVM, but function calls are generally considered to be pretty quick as long as the target is the same every time (so it is static, direct or monomorphic call). For this reason we don’t have to / shouldn’t make a function inlined just because we use it frequently. Kotlin compiler even generates a warning if using `inline` like this. I sometimes suppress the warning if creating functions like: `inline fun isNotEmpty() = !isEmpty()`

However, calls are much slower if the target often changes and this is a typical case for higher-order functions. We use the same higher-order function passing various lambdas to it, so it has to do dynamic lookups every time. And if it is a function like `Iterable.map()` then it has to call the lambda multiple times per a single higher-order call, so it is even worse. In these cases it makes sense to inline the function for performance reasons.

---

<div class="post-metadata">

**Author:** ![alexander.kot](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@alexander.kot](https://discuss.kotlinlang.org/u/alexander.kot)\
**Post date:** [January 8, 2023, 10:58am UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/11 "2023-01-08T10:58:10Z")

</div>

Thank you, now everything becomes clear.  
Thanks for the decompiler advice also.

---

<div class="post-metadata">

**Author:** ![alexander.kot](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@alexander.kot](https://discuss.kotlinlang.org/u/alexander.kot)\
**Post date:** [January 8, 2023, 11:09am UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/12 "2023-01-08T11:09:22Z")

</div>

Broot, thank you too!

Are you sure this is good example:  
inline fun isNotEmpty() = !isEmpty()  
Is not a high-order function.

You mentioned the reified keyword. Can you explain why it should be used with inline together?

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [January 8, 2023, 12:36pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/13 "2023-01-08T12:36:53Z")

</div>

> [@alexander.kot](#):
>
> Are you sure this is good example:  
> inline fun isNotEmpty() = !isEmpty()  
> Is not a high-order function.

This is exactly my point. Generally, we should use `inline` only for higher-order functions or if using features that require inlining (reified, non-local returns) - in other cases Kotlin compiler assumes inlining is unnecessary and generates a warning. Despite this fact, I sometimes decide to still inline even if “unnecessary”, especially if I create very small utility functions like above. But frankly. I’m not sure if it makes any sense or not and I don’t suggest others to do the same.

> [@alexander.kot](#):
>
> You mentioned the reified keyword. Can you explain why it should be used with inline together?

I don’t want to go into deep details, but for technical reasons reification is possible only if the function is inlined.

---

<div class="post-metadata">

**Author:** ![alexander.kot](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@alexander.kot](https://discuss.kotlinlang.org/u/alexander.kot)\
**Post date:** [January 8, 2023, 12:38pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/14 "2023-01-08T12:38:55Z")

</div>

Thank you

---

<div class="post-metadata">

**Author:** ![Gor\_Madatyan](https://avatars.discourse-cdn.com/v4/letter/g/b5a626/32.png) [@Gor\_Madatyan](https://discuss.kotlinlang.org/u/Gor_Madatyan)\
**Post date:** [August 27, 2024, 1:39pm UTC](https://discuss.kotlinlang.org/t/noinline-va-crossinline-can-you-clarify/26175/15 "2024-08-27T13:39:21Z")

</div>

Even in official docs is said that there is sense to use inline for optimizing high-order functions  
[https://kotlinlang.org/docs/inline-functions.html](https://kotlinlang.org/docs/inline-functions.html)
