Lambdas and implicit references to the instance of the enclosing class


#1

Hi,

I have a simple question. Unfortunately, I didn’t find a clear answer in the documentation.

Please can you clarify is an implicit reference to the instance of the enclosing class always created when we use lambda expressions? For example, in Java there are two different situation:

  • Anonymous inner classes always create implicit reference

  • Java 8 lambdas create implicit reference only when we are using some method or field from the enclosing class

The clarification of Kotlin’s lambdas behavior is really important to prevent possible memory leaks (e.g., when passing lambdas to rx operators).


#2

The “Show Kotlin Bytecode” view is very helpful for answering such questions, if you can read bytecode at least (it’s not that hard). You can open it in the tools menu.

Like in Java, what happens in Kotlin varies in different cases.

  • If the lambda is passed to an inline function and isn’t marked noinline, then the whole thing boils away and no additional classes or objects are created.
  • If the lambda doesn’t capture, then it’ll be emitted as a singleton class whose instance is reused again and again (one class+one object allocation).
  • If the lambda captures then a new object is created each time the lambda is used.

Thus it is similar behaviour to Java except for the inlining case where it’s even cheaper. This efficient approach to encoding lambdas is one reason why functional programming in Kotlin is more attractive than in Java.

Note, however, the following caveat. Currently the Kotlin compiler does not use the Java 8 invokedynamic infrastructure for spinning lambda classes at runtime. Thus whilst Kotlin lambdas are comparable in terms of runtime performance to Java, they take up more space on disk and require more class files in the shipped JARs which in turn imposes a small load time penalty, as it’s faster to create code entirely in memory on-demand than load and decompress from a ZIP file. The Kotlin team plan to start emitting Java 8 style bytecode in future.

Switching to Java 8’s LambdaMetaFactories via invokedynamic unlocks other benefits: it takes less RAM and creates less lock contention inside the JVM itself. A future version of HotSpot is planned to continue to improve the efficiency of lambdas:

http://openjdk.java.net/jeps/8158765


#3

Thank you for such a comprehensive response! This is just what I was looking for.

I agree, the “Show Kotlin Bytecode” feature could be helpful in this case. But, I think, this information should be added to the documentation anyway. You know, people can be lazy sometimes :slight_smile:


#4

Does the observation about Kotlin compiler not using JVM’s invokedynamic for lambdas also apply to the Dalvik equivalents invoke-custom and invoke-polymorphic?