Strange behaviour of functions from Standard.kt


#1

Here some code example (sorry, haven’t figured out how to attach properly)
Issue:
I can write e.apply{…} (or any other function from Standard.kt) and have no warnings that function in this case would be applied to component but not to the event. Seems a bit strange.

Am I missing some language concepts?

1


#2

This behavior is not strange, but is as intended. The lambda is applied to the event (i.e. this points to the event). But all variables and functions in scope outside of the lambda remain available inside of the lambda.


#3

I understand, that when I write e?. apply this refers to event
But also I can write, as said, e.apply and * this * would refer to component, no warnings, not prohibited, why? It’s meaningless in the context and caused a bug, that’s why I am interested in understanding.
Moreover it’s unsafe call.


#4

The explanation of this behavior is here: https://kotlinlang.org/docs/reference/lambdas.html#closures


#5

this will never point to the component. It looks like this points to the component because you can still access the component’s properties and functions, but this access is possible due to scope and not because this points to the component.

Try the following code and the compiler will report an error because clickPoint is not a member of the event:

this.clickPoint.x = this.x.toDouble()

#6

Yes, I had such results when playing around, thank you for explanation!
So combined with answer by @forinil2 am I understanding the situation right now?

When I write e.apply kotlin thinks it’s called on smth like null and prohibits the access to events properties/functions but due to component closure I have access to all that component holds?


#7

No, if e is null the lambda passed to apply won’t be invoked at all, because this can never be null. You can test this at https://try.kotlinglang.org/ with the following code. It will not produce output:

fun main(args: Array<String>) {
    val e: String? = null
    e?.apply {
        println(this.length)
    }
}

When e is not null, Kotlin uses the following order to determine to which property or function a name refers to (note: this list is very likely to be incomplete):

  1. Local variables inside lambda
  2. Members of this, which in this case is an instance of MouseEvent
  3. Local variables and parameters of mouseClicked(...)
  4. Members of CaptureComponent
  5. Imported properties and functions

#8

Here I go)

val length = 10

fun main(args: Array) {
val e: String? = null
e.apply {
println(length)
}
}

Outputs 10)
Now I will be more careful :slight_smile:

And would you be so kindly to explain me how to add code to message properly)


#9

Three backticks then name of programming language (eg. ```kotlin ) then new line then code then newline, three backticks and new line again.

Just like Markdown :slight_smile:


#10
fun main(args: Array) {
  println("Thanks!")
}

#11

Sorry, my bad. The conditional operator (?.) prevents execution of the lambda, but this can indeed be null if you do not execute conditionally.

The compiler probably sees that e is nullable, and will then decide that accessing length will result in an error and pick the next available length that can be invoked unconditionally. I am not sure whether this is a compiler bug or not, and that the correct compiler behavior is to report an error that you tried to access a property on a nullable value.

If it is not a bug, then it simply is one of the Kotlin rules you (and, as can be concluded from my erroneous answer above, I too) have to learn.

If you feel that it is confusing, you can always use an if:

if (e != null) {
    clickPoint.x = e.x.toDouble()
    clickPoint.y = e.y.toDouble()
}