Martin Devillers
05/21/2019, 12:52 PMMartin Devillers
05/21/2019, 12:53 PMMartin Devillers
05/21/2019, 12:54 PMf that gets called is the one in A, which is counterintuitive, I would expect the one in B.Martin Devillers
05/21/2019, 12:54 PMmarstran
05/21/2019, 1:05 PMoverride modifier). They're just overloads. I'm guessing the f in B gets name-mangled or something during compilation so it works after type erasure.Martin Devillers
05/21/2019, 1:44 PMoverride, the method binding happens at compile-time, and it’s the compiler which chooses to bind to the method in A rather than the one in B. It’s just strange that it chooses to do so.Ilmir Usmanov [JB]
05/21/2019, 3:16 PMdsavvinov
05/21/2019, 3:19 PMA.f is more specific than B.f, because they differ only in parameter of accepted lambda, which is a contravariant position.
In other words, A.f accepts only lambdas which operate on A, while B.f accepts lambdas which operate both on A and B.
This similar to how we choose f(Int) over f(Any) in f(42), but lambda makes it much more confusing (and, honestly, I also thought that something is wrong here at first 😅 )Martin Devillers
05/21/2019, 3:45 PMclass A twice? In practice, it doesn’t, it prints class A then class B.
open class A
class B: A()
fun f(block: (A) -> Unit) = A()
fun f(block: (B) -> Unit) = B()
fun main() {
val blockA: (A) -> Unit = {}
val blockB: (B) -> Unit = {}
println(f(blockA)::class)
println(f(blockB)::class)
}dsavvinov
05/21/2019, 3:49 PMf(block: (A) -> Unit) can not accept blockB — again, theoretically speaking, this is because parameters are contravariant. And speaking more practically, body of blockB treats parameter as B, while f(block: (A) -> Unit) may pass here something which is not B (e.g., instance of A)Martin Devillers
05/21/2019, 3:56 PMMartin Devillers
05/21/2019, 3:57 PM