2017-12-15 8:02 GMT+01:00 Jochen Theodorou <blackdrag@gmx.org>:
On 15.12.2017 06:10, Nathan Harvey wrote:
I think your first step - "define a file that contains extension functions" -
is slightly wrong. In Kotlin, you can place extension methods anywhere, they
do not have to be confined to a single file (or worse, like Groovy, in a
totally different dependency). The syntax I discussed is what enables them
to do this.

I am aware of that you can define them anywhere. But frankly, I find that pretty messy. I mean defining quasi global extension methods randomly all over the place... does sound like maintenance hell to me. Probably best to declare them inline as well, then you will never ever be able to find them again, if they are from a library.

I disagree here. The fact that you can define extension methods locally in Kotlin is a huge win, especially for DSLs. Unlike Groovy they are local, so don't leak to other parts of the application. So you can define extensions that will "enhance locally" something, and it's pure awesomeness. Take this example:

class DecoratedTasks(val delegate: TaskContainer) : TaskContainer by delegate {
    companion object {
        fun of(tasks: TaskContainer, block: DecoratedTasks.() -> Unit) =
            block(DecoratedTasks(tasks))
    }

    inline operator
    fun <reified T: Task> String.invoke(configuration: T.() -> Unit) =
        (getByName(this) as T?)?.run { configuration(this) }
}

fun TaskContainer.configure(block: DecoratedTasks.() -> Unit) = DecoratedTasks.of(this, block)

which allows us to use this:

tasks.configure {
    "jar"<Jar> {
        archiveName = "foo"
    }
}

Note how the "String invoke" operator is overriden locally. It only makes sense in this context, and everything is statically typed. I think it's a huge win.