I tried this code on Kotlin playground (Kotlin version 1.4.30):
class A() {
var i: Int? = null
set(v) {
v ?: run {
field = 7
return
}
field = v
}
}
fun main() {
val i: Int? = null
i ?: run {
val a = A()
a.i = null
print("a.i: ${a.i}; ")
}
println("i: $i")
}
and the output was as expected, a.i: 7; i: null
.
If I replaced run
in the statement i ?: run {
to let
, also
, or apply
, I got an Unresolved reference
error, also as expected.
However, if I replaced the run
in the statement v ?: run {
with any of let
, also
, or apply
, I didn’t get an error message. Instead I got the original output, a.i: 7; i: null
in all cases.
Is this the expected behavior? Are the scope functions supposed to behave differently in a property setter? If so, is this a documented behavior? Thanks.
There’s two run
functions. One is an extension method like let
, also
, and apply
. The other is not an extension methods. In the property setter, you can call extension methods because this
is available as the receiver. In main, there is no this
so you cannot call extension methods without explicitly providing one (a.let {...}
). But the non-extension run
works fine.
While they work similarly, your two calls to run
are actually calling different implementations. The name is just overloaded. You can see both listed in the documentation
3 Likes
Thanks for the answer. I missed the implied this.
in the primary constructor.
A follow up question:if instead of field = v
in the setter , I have field = if (v < 0) 0 else v
, like so:
class A() {
var i: Int? = null
set(v) {
v ?: run {
field = 7
return
}
field = if (v < 0) 0 else v
}
}
the compiler doesn’t complain if I use run
or let
, but with apply
and also
it complains of:
Operator call corresponds to a dot-qualified call ‘v.compareTo(0)’ which is not allowed on a nullable receiver ‘v’.
Somehow let
and run
result in v
being smart cast but not apply
and also
? Is it because the compiler can choose the unwrapped Int
over Unit
in the former case but couldn’t decide between the unwrapped Int
and A
, which is the type of this
returned by apply
and also
?
Thanks.
Ok, the compiler gives the same error message with let
and run
if I replace return
in the setter with v
or A()
, like so:
v ?: run {
field = 7
A() // or v
}
It looks like it can smart cast v
after the elvis statement only if there’s no alternative type.
1 Like