Member extension resolution

seems a little strange to me:

open class A

interface I { fun A.foo() }

fun main() {
    val a = object : A(), I { override fun A.foo() = TODO() }

    a.foo() // error. foo is not resolved

    a.apply { foo() } // OK
}

Is there any explanation?

That’s a somewhat unusual scenario.

My take is that foo is a function that can be called only when you have an I in scope, that is usually while you’re implementing methods of I itself.
I can only infer that also an extension function on an instance of I can access that member (which seems useful for DSLs)

When creating an anonymous class with multiple ancestor types you need to specify the only type your object is!

Otherwise create a class B exactly for that purpose:

class B : A(), I

Let the object extend B and everything will work fine because B contains the notion of both A and I, while an anonymous object cannot (unless you cast, but when you do, you lose the other type!)

You mean this?

open class A

interface I { fun A.foo() }

open class B: A(), I { override fun A.foo() = TODO() }

fun main() {
    (object : B() {}).foo() // error
    B().foo() // error
}

It doesn’t work either

1 Like

An interesting case. Your method foo actually has two receivers. A member receiver I and an extension receiver A. According to current rules, the function has two arguments, and when you provide only one (event if it satisfies both types) it is not recognized.

When we were discussing KEEP-176, we proposed different rules, when one object could be recognized as multiple receiver types at once, but it requires a slight change of ideology.

6 Likes

BTW, is there any progress on compound extensions/typeclasses dillema? I thought typeclasses got the green light since @abreslav mentioned them in a public talk

Type-classes are not a solid concept, even KEEP-87 team stopped to use the term. Type classes are invented for haskel and are not quite useful as themselves in a language with inheritance. As for contextual extensions, we will see what route language community will take. Both KEEP-176 and KEEP-87 cover significant portion of use-cases, but the approach is different.

1 Like

I must have missed that talk. Do you have a link or at least know when this talk was?

Unfortunately, I completely forgot where it was. All I remember is that it was in russian.

As far as I remember, he mentioned them on the closing panel on the kotlinconf-2019. But as I already said, type-classes is a general concept that could not ( and should not) be ported to Kotlin as is. There are different ways to achieve the same functionality. File-level receivers I mentioned in KEEP-176 discussion, provide quite similar functionality without introducing implicit lookup table. I think that everybody want some kind of contextual behavior abstraction, but I do not think that there is a clear path to it.

2 Likes