Interfaces with extension functions defined


#1

My coworker recently sent a pull request which had interfaces that had extension functions defined so he could treat them as “mix-ins” for behavior by implementing them in our own types.

A contrived example might look something like

interface C {
    fun Int.hello() = println(1)
}

class D: C {
    override fun Int.hello() = println(2)
}

class E: C


fun printFoo(c: C) {
    with(c) {
        5.hello()
    }
}

fun main(args: Array<String>) {
    printFoo(D())
    printFoo(E())
}

I was a bit surprised to see this allowed by the compiler. I also thought this would fall into the limitation of Extensions are resolved statically as I didn’t see any other documentation for it.

To my surprise, this printed out

2
1

I think this could possibly be useful for DSL-type builders, but found it a bit unnatural and surprising. I don’t think I’ve seen it in any well known libaries (yet). What is the motivation for allowing interfaces to define extension method methods?


#2

Extensions are resolved statically regarding to the Int class in your example. Not from the class they’re declared in. Quoting from the documentation:

Extensions declared as members can be declared as open and overridden in subclasses. This means that the dispatch of such functions is virtual with regard to the dispatch receiver type, but static with regard to the extension receiver type.

I think it helps to think of an extension function as a completely normal function that specifies its first parameter in a slightly irregular way.
So

would actually be pretty much the same as


#3

Good catch on the documentation. If I would have just looked further down the page, I would have seen that section as well :man_facepalming:.

When I looked at the bytecode I noticed that it compiles (basically) to your fun hello(this: Int) = println(1) definition. The quoted documentation you link explains this pretty clearly.

I do wonder how useful allowing this type of code is. Any popular libraries making use of this? Would be useful to see if I’m unimaginative and how this could be applied in a real codebase.


#4

There is video from a while back. If I remember correctly, it encourages moving things into extension functions. I can’t seem to find it… Maybe someone more in tune with their Google-fu can find it? I think it was a talk by Andrey Breslav from a few years back.