Search code examples
kotlinfunctional-interface

Function interface in Kotlin 1.4


This feature will be coming Kotlin 1.4. Here is an excerpt from KotlinConf'19.

fun interface Action {
    fun run()
}

fun runAction(a: Action) = a.run()

runAction{
    println("Hello")
}

It looks nice, but I still don't know what it does.

What is the function interface? What is its practical value? What specific scenarios can it be used for?


Solution

  • This is about functional interfaces — interfaces with a Single Abstract Method (also called SAM interfaces).

    To understand the point, I'll need to cover a little history…  In Java, lambdas were added relatively recently.  Before that, you implemented callbacks and similar by implementing a suitable interface.  For example, if you wanted to be informed when an AWT component was actioned, you'd create an object which implemented the ActionListener interface.  That has a single method (called actionPerformed()); you'd put your code inside that method:

    myButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            // Do something
        }
    });
    

    When they added lambdas, they wanted to blend in with all the existing code, and change as little as possible, so they did it exactly the same way: the compiler infers which interface you're implementing, and creates an object implementing that interface.  You could write:

    myButton.addActionListener(e -> {
        // Do something
    });
    

    which is shorter — but it compiles down to pretty much the same as the first example.

    So in Java, functions are not first-class objects; lambdas are simply a more concise way to implement functional interfaces.

    In Kotlin, however, functions are first-class objects: you can write a lambda (or an anonymous function) on its own, assign it, pass it to functions, return it from functions, and so on — so there's no need for SAM interfaces at all!

    For easier interoperability with Java, Kotlin lets you easily implement Java SAM interfaces, in the same way you do from Java:

    myButton.addActionListener {
        // Do something
    }
    

    But Kotlin <= 1.3 doesn't let you implement Kotlin interfaces that way; you need to implement those explicitly.  (I suspect this was partly to encourage developers to use proper functions, with all their other advantages, and not rely on the Java-style workaround.)

    Your example illustrates this.  It has an interface (Action) with one abstract method (run()).  It has a function (runAction()) which takes an instance of that interface.  And it has some code which wants to call that function, passing just the code for the run() method.

    In Kotlin <= 1.3, you'd have to do the latter explicitly, e.g.:

    runAction(object : Action {
        override fun run() {
            println("Hello")
        }
    })
    

    But from Kotlin 1.4, you can mark the interface as fun interface, and use the Java-style shortcut, as in your example.

    (You may or may not think this is a good thing…)