0

In kotlin, I'm trying to create a dispatch table:

class Foo {
    fun handleEvent(bytes:ByteArray) {
        // do something fun with the bytes
    }
}

class Bar {
    fun handleEvent(bytes:ByteArray) {
        // do something fun with the bytes
    }
}

foo = Foo()
bar = Bar()

val eventHandlers:HashMap<RemoteEvent, (bytes:ByteArray)->Unit> = hashMapOf(
    0x01 to foo.handleEvent,
    0x02 to bar.handleEvent)

Kotlin doesn't seem to like this, it complains in multiple ways, but the relevant one seems to be be function invocation expected.

I can fix this by wrapping those in closures:

val eventHandlers:HashMap<RemoteEvent, (bytes:ByteArray)->Unit> = hashMapOf(
    0x01 to { bytes -> foo.handleEvent(bytes) },
    0x02 to { bytes -> bar.handleEvent(bytes) })

Is there no other way? Why do I have to the method signatures, which are correct, in closures which are the same? Are closures and methods not on the same footing in Kotlin?

Salem
  • 13,516
  • 4
  • 51
  • 70
Travis Griggs
  • 21,522
  • 19
  • 91
  • 167

2 Answers2

4

In Kotlin, function references are created with the :: operator (not .).

Your intended use case can easily be achieved using this:

val eventHandlers: HashMap<RemoteEvent, (bytes: ByteArray) -> Unit> = hashMapOf(
        0x01 to foo::handleEvent,
        0x02 to bar::handleEvent)
                 // ^

Function references, Kotlin docs

foo.handleEvent is interpreted as accessing the property called handleEvent (which doesn't exist.)

foo::handleEvent is a KFunction instance representing the function called handleEvent, and since this matches the lambda signature (ByteArray) -> Unit it works as expected.

Notice that this is different from e.g. C# or C++, where due to language restrictions, methods and properties/fields cannot share the same name. In these languages . is fine for method groups/function pointers because it is impossible that foo.bar would be ambiguous.

Salem
  • 13,516
  • 4
  • 51
  • 70
0

Without closures expression is evaluated (invoked) in line.

Closures generate an anonymous object with defined method (within closures) that can be invoked when needed.

Only exception is when function consuming the lambda is declared as inline in which case entire function block is injected into calling place, including the lambda (to prevent generating object).

Pawel
  • 15,548
  • 3
  • 36
  • 36