0

I am looking into optimizing the size of the call stack by using inline functions.

If you execute the following code:

inline fun function2( action: () -> Unit) {
 action()
}

fun function1() {

 function2{ printCurrentStack() }
}

fun printCurrentStack() {
 RuntimeException().printStackTrace()
}

fun main() {
 function1()
}

You will get the following output:

at com.kotlin.playground.functional.PrimeNumbersKt.printCurrentStack(PrimeNumbers.kt:17)
at com.kotlin.playground.functional.PrimeNumbersKt$function1$1.invoke(PrimeNumbers.kt:13)
at com.kotlin.playground.functional.PrimeNumbersKt$function1$1.invoke(PrimeNumbers.kt)
at com.kotlin.playground.functional.PrimeNumbersKt.function2(PrimeNumbers.kt:8)
at com.kotlin.playground.functional.PrimeNumbersKt.function1(PrimeNumbers.kt:13)
at com.kotlin.playground.functional.PrimeNumbersKt.main(PrimeNumbers.kt:21)
at com.kotlin.playground.functional.PrimeNumbersKt.main(PrimeNumbers.kt)

So, in this case, the stack has 7 elements.

  • Calling main
  • Calling function1
  • Calling function2
  • 2 calls for the lambda expression
  • Calling printCurrentStack
  • Calling printStackTrace

Now, if I mark function2 as inline and I execute the code, I get the following output:

at com.kotlin.playground.functional.PrimeNumbersKt.printCurrentStack(PrimeNumbers.kt:17)
at com.kotlin.playground.functional.PrimeNumbersKt.function1(PrimeNumbers.kt:13)
at com.kotlin.playground.functional.PrimeNumbersKt.main(PrimeNumbers.kt:21)
at com.kotlin.playground.functional.PrimeNumbersKt.main(PrimeNumbers.kt)

This seems to work great, the size of the call stack is reduced by 3.
However, if I update function1 to store the lambda in a variable before sending it to function2:

fun function1() {
 val lambda = { printCurrentStack() }
 function2(lambda)
}

The output changes to this:

at com.kotlin.playground.functional.PrimeNumbersKt.printCurrentStack(PrimeNumbers.kt:15)
at com.kotlin.playground.functional.PrimeNumbersKt$function1$lambda$1.invoke(PrimeNumbers.kt:10)
at com.kotlin.playground.functional.PrimeNumbersKt$function1$lambda$1.invoke(PrimeNumbers.kt)
at com.kotlin.playground.functional.PrimeNumbersKt.function1(PrimeNumbers.kt:21)
at com.kotlin.playground.functional.PrimeNumbersKt.main(PrimeNumbers.kt:19)
at com.kotlin.playground.functional.PrimeNumbersKt.main(PrimeNumbers.kt)

The size of the call stack goes from 4 to 6 although function2 is still marked as an inline function.

It seems that the lambda calls cannot be inlined if the lambda is stored in a variable.
Why is this happening?

Dimitar Spasovski
  • 2,023
  • 9
  • 29
  • 45
  • 2
    Storing it in a variable creates a functional object for the lambda so it can be stored. It's the object that the variable is pointing to in memory. – Tenfour04 Jan 24 '21 at 22:31
  • @Tenfour04 Thanks for the answer. So, isn't that functional object immutable? If it is, then what is stopping kotlin from being able to copy the lambda and inline it? – Dimitar Spasovski Jan 27 '21 at 21:56
  • By assigning it to a variable, you are explicitly telling the compiler to assign it to a variable. Whether the JVM inlines it at runtime is another matter. It may very well do that, but I'm not an expert. – Tenfour04 Jan 27 '21 at 21:58

0 Answers0