Edit (February 19, 2017): I received a very detailed answer from Mike Hearn on this issue.
As in Java, what happens in Kotlin differs in different cases.
- If the lambda is passed to the built-in function and noinline is marked, then all this will boil, and no additional classes or objects are created.
- If the lambda is not fixed, then it will be selected as a singleton class, an instance of which is used again and again (one class + one distribution object).
- If lambda captures, then a new object is created every time a lambda is used.
So this is the same behavior with Java, except in the case of addition where it is even cheaper. This efficient approach to lambda coding is one of the reasons why functional programming in Kotlin is more attractive than in Java.
Edit (February 17, 2017): I posted a question on this topic in Kotlin discussions . Perhaps Kotlin engineers will bring something new to the table.
are kotlin lambdas just converted to Java Anonymous functions?
I asked this question myself (one simple correction here: they are called anonymous classes, not functions). There is no clear answer in the Koltin documentation. They are just state , which
Using functions of a higher order imposes certain penalties at runtime: each function is an object, and it captures a closure, that is, these variables that are available in the body of the function.
This is a bit confusing what they mean by variables that are available in the body of the function. Is reference to instance of inclusion class taken into account?
I saw a topic that you refer to in your question, but it seems to be out of date. I found more relevant information here :
Lambda expression or anonymous function retain implicit references spanning class
So, unfortunately, it seems that Kotlin lambdas have the same problems as Java Anonymous Inner Classes.
Why are anonymous inner classes bad?
From Java specs :
The instance i of the direct inner class C of class O is associated with the instance of O, known as the immediate instance of i. The attached instance of the object, if any, is determined when the object is created
This means that an anonymous class will always have an implicit reference to an instance of the incoming class. And since the link is implicit, there is no way to get rid of it.
Look at a trivial example
public class YourActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new Thread(new Runnable() {
As you can see, in this case there will be a memory leak until a lengthy task is completed. A workaround for this is to use a static nested class.
Since Kotlin's non-inlined lambdas contain a reference to an instance of the surrounding class, they have similar problems with memory leaks.
Bonus: quick comparison with other lambda implementations
Java 8 Lambdas
Syntax:
Declare a SAM interface (single abstract method)
interface Runnable { void run(); }
Use this interface as type for lambda
public void canTakeLambda(Runnable r) { ... }
Pass your lambda
canTakeLambda(() -> System.out.println("Do work in lambda..."));
Memory leak problems: As indicated in the specification :
References to this — including implicit references through unqualified field references or method calls — are essentially references to the final local variable. Lambda bodies that contain such references capture the corresponding instance of this. In other cases, a reference to this is not stored by the object.
Simply put, if you are not using any fields / methods from the enclosing class, there is no implicit reference to this , as is the case with anonymous classes.
Retrolambda
From docs
Lambda expressions are passed back by converting them to anonymous inner classes. This includes optimizing the use of a singleton instance for lambda expressions without apathy to avoid re-distribution.
I think this is self-evident.
Apple swift
Syntax:
The declaration is similar to Kotlin, in Swift lambdas are called closures:
func someFunctionThatTakesAClosure(closure: (String) -> Void) {}
Skip closing
someFunctionThatTakesAClosure { print($0) }
Here $0 refers to the first argument of the String closure. This corresponds to it in Kotlin. Note. Unlike Kotlin, in Swift we can also refer to other arguments, such as $1 , $2 , etc.
Memory leak problems:
In Swift, as in Java 8, a closure captures a strong reference to self ( this in Java and Kotlin) only if it accesses an instance property, such as self.someProperty , or if the closure calls a method on the instance, such as self.someMethod() .
Also, developers can easily indicate that they want to capture only a weak link:
someFunctionThatTakesAClosure { [weak self] in print($0) }
I would like it to be possible in Kotlin :)