Kotlin generics


#1

I thought I understood generics in Kotlin. Clearly I do not. Can anyone offer clarification on this:

The JavaFX library includes an interface for defining handlers
for events of a specific class/type:

  interface EventHandler<T extends Event> {
  void handle(T event)
  }

A handler for ActionEvents to be used with buttons is:

  val actionHandler: EventHandler<ActionEvent> = object: EventHandler<ActionEvent> {
  override fun handle(event: ActionEvent?): Unit { /* do nothing */ }
  }

BUT, to define a handler for MouseEvents requires a completely different
structure:

/**

  • Interface:
  •   interface EventHandler<T extends Event> {
  • &nbsp;&nbsp;void handle(T event)
    
  •   }
  • Hierarchy:
  •   Event
  • &nbsp;&nbsp;ActionEvent
    
  • &nbsp;&nbsp;InputEvent
    

*           MouseEvent
*           KeyEvent
*/

import javafx.event.*
import javafx.scene.input.*

fun main(args: Array<String>) {
  val actionHandler: EventHandler<ActionEvent> = object: EventHandler<ActionEvent> {
  override fun handle(event: ActionEvent?): Unit { /* do nothing */ }
  }

  val mouseHandler: EventHandler<in MouseEvent?> = object: EventHandler<MouseEvent?> {
  override fun handle(event: MouseEvent?): Unit { /* do nothing */ }
  }
}

Help!


#2

Why can't you define a handler for MouseEvent in a same way?

  val mouseHandler: EventHandler<MouseEvent> = object: EventHandler<MouseEvent> {   override fun handle(event: MouseEvent?): Unit { /* ... */ }   }


#3

The handler can be defined as for the action handler. However, the compiler gives an error on the node.setOnMousePressed(handler) statement.

fun fromMouseEventsOf(node: Node): Observable<MouseEvent> {
  return Observable.create(object: Observable.OnSubscribeFunc<MouseEvent> {
  override fun onSubscribe(observer: Observer<in MouseEvent>?): Subscription? {
           //val handler: EventHandler<in MouseEvent?> = object: EventHandler<MouseEvent?> {
           //   override fun handle(event: MouseEvent?): Unit = observer?.onNext(event)
           //}
           val handler: EventHandler<MouseEvent> = object: EventHandler<MouseEvent> {
           override fun handle(event: MouseEvent?): Unit = observer?.onNext(event)
           }
           node.setOnMousePressed(handler)

           return createSubscription{ ->
           node.setOnMousePressed(null)
           }
  }
  }) as Observable<MouseEvent>
}

The error is:

Type mismatch.

Required: EventHandler<in MouseEvent?>?
Found: EventHandler<MouseEvent>

Can you enlighten me?


#4

The problem is that Node.setOnMousePressed() method expects parameter of type EventHandler<in MouseEvent?>?, which means that it accepts EventHandler with any supertype of MouseEvent? in angle brackets. MouseEvent is not a subtype of MouseEvent?, so EventHandler<MouseEvent> is not a subtype of EventHandler<in MouseEvent?>

What you can do about it:

  • subclass from EventHandler<MouseEvent?> or EventHandler<in MouseEvent?>;
  • provide external annotations with different signature for Node.setOnMousePressed(): setOnMousePressed(EventHandler<in MouseEvent>).