Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the code in an object expression can access variables from the scope that contains it in kotlin?

Tags:

kotlin

In Kotlin,the code in an object expression can access variables from the scope that contains it, just like the following code:

fun countClicks(window: JComponent) {    var clickCount = 0    var enterCount = 0    window.addMouseListener(object : MouseAdapter() {     override fun mouseClicked(e: MouseEvent) {         clickCount++     }      override fun mouseEntered(e: MouseEvent) {         enterCount++     }    }) } 

But why? In Java, it's not allowed to do this, because the life cycle of the object is different from the local variables, so the enterCount or clickCount maybe be invalid when you try to access the object. Can someone tell me how Kotlin does this?

like image 498
LingoGuo Avatar asked Jun 14 '17 07:06

LingoGuo


People also ask

What is the use of scope function in Kotlin?

Scope functions The Kotlin standard library contains several functions whose sole purpose is to execute a block of code within the context of an object. When you call such a function on an object with a lambda expression provided, it forms a temporary scope. In this scope, you can access the object without its name.

How can the apply function in Kotlin be used to configure an object?

In Kotlin, apply is an extension function on a particular type and sets its scope to object on which apply is invoked. Apply runs on the object reference into the expression and also returns the object reference on completion.

Which is the following is returned by scope function also in Kotlin?

'apply' and 'also' functions return the context object itself. In this case, we don't need to specify the return value. The context object is automatically returned. Check the below table for the comparison.

What does ?: Mean in Kotlin?

In certain computer programming languages, the Elvis operator ?: is a binary operator that returns its first operand if that operand is true , and otherwise evaluates and returns its second operand.


2 Answers

In Java, you can only capture (effectively) final variables in anonymous classes and lambdas. In Kotlin, you can capture any variable, even if they are mutable.

This is done by wrapping any captured variables in instances of simple wrapper classes. These wrappers just have a single field that contains the captured variables. Since the instances of the wrappers can be final, they can be captured as usual.

So when you do this:

var counter = 0 { counter++ }()   // definition and immediate invocation, very JavaScript 

Something like this happens under the hood:

class Ref<T>(var value: T) // generic wrapper class somewhere in the runtime  val counter = Ref(0);      // wraps an Int of value 0 { counter.value++ }()      // captures counter and increments its stored value 

The actual implementation of the wrapper class is written in Java, and looks like this:

public static final class ObjectRef<T> implements Serializable {     public T element;      @Override     public String toString() {         return String.valueOf(element);     } } 

There are also additional wrappers called ByteRef, ShortRef, etc. that wrap the various primitives so that they don't have to be boxed in order to be captured. You can find all the wrapper classes in this file.

Credits go to the Kotlin in Action book which contains the basics of this information, and the example used here.

like image 84
zsmb13 Avatar answered Sep 22 '22 22:09

zsmb13


In Kotlin, unlike Java, lambda expressions or anonymous function (as well as local functions and object expressions) can access and modify their closure - variables declared in outer scope. This behavior is as-designed.

Higher order functions and lambdas - Closures

Why Java does not allow this and Kotlin does - capturing closures introduces additional run-time overhead. Java uses simple and fast approach at cost of functionality. Kotlin on the other hand gives you more features - functionality, but it also generates more code behind the scenes to support it.

At the end it is about writing less code to achieve something. If you want to translate above code to Java, it would be more complex.

like image 38
Dalija Prasnikar Avatar answered Sep 20 '22 22:09

Dalija Prasnikar