JavaFX Tutorials

Saturday, December 3, 2016

Kotlin Callable Reference Notes

Method references were added to Java 8 and you may already be using the double-colon (::) syntax to use a method reference as a parameter.  The semantics in Kotlin are different although a change in 1.1 will address these differences.

This article presents a few examples of passing function references in Kotlin 1.0.

This function from an object Notifications accepts a function as the third parameter.
    
object Notifications {
    fun subscribe(event : String, subscriber : Any, cb : (String) -> Unit) {
        // implementation

If you have a class with a function "refresh", you might expect to code the following based on how Java 8 works and the Kotlin documentation.

class RolesViewModel {

    init {
        Notifications.subscribe(EVENT_MODEL_UPDATE_LOGGED_OUT, this, ::refresh);
    }

    fun refresh(event : String) {
        println("refresh")
    }
}

However, you'll get the following error on the ::refresh token.

Left-hand side of a callable reference with a receiver parameter cannot be empty.  Please specify the type of the receiver before '::' explicitly.

This is a feature being added to 1.1 as described on JetBrains YouTrack.  In the meantime, you can use the following.

Double-Colon

As in the Kotlin documentation, you can define a function within the code block and use the double-colon ("::") syntax.  Note that this function is not a class member.

class RolesViewModel {

    init {
        fun rf2(e : String) = println(e)

        Notifications.subscribe(EVENT_MODEL_UPDATE_LOGGED_OUT, this, ::rf2)
    }

Function Variable

Alternatively, you can define a function variable as the parameter.

class RolesViewModel {
  
    private val rf = {
        e : String -> println(e)
    }

    init {
        Notifications.subscribe(EVENT_MODEL_UPDATE_LOGGED_OUT, this, rf)
    }

Lambda

A Lambda is also an option, although you won't have a handle to the function object.

class RolesViewModel {

    init {
        Notifications.subscribe(
           EVENT_MODEL_UPDATE_LOGGED_OUT, 
           this, 
           { event -> refresh(event) } 
        )
    }

    fun refresh(event : String) {
        log.fine("refresh")
    }

Since the function parameter of subscribe() has a single argument, the Lambda can be rewritten to use the "it" syntax".

class RolesViewModel {

    init {
        Notifications.subscribe(
          EVENT_MODEL_UPDATE_LOGGED_OUT, 
          this, 
          { refresh(it) } 
        )
    }

    fun refresh(event : String) {
        log.fine("refresh")
    }

Kotlin 1.1 has a fix for left-hand assignments.  I assume that the fix will include support for "this" as well as other objects.  If you're still on 1.0, this post showed a few workarounds so that your functions can be passed around.

No comments:

Post a Comment