Search code examples
scalauser-interfacecontinuationscontinuation-passing

Event listeners with Scala continuations


Suppose I have to write some GUI code as follows:

widget1.addListener(event1 =>
   handle1(event1)
   widget2.addListener(event2 =>
     handle2(event2)
     widget3.addListener(event3 => handle3(event3))
   )
)

How would you write it in CPS-style using Scala continuations?


Solution

  • Just wanted to provide working example in addition to other answers. With Scala continuations it can look like this:

    import scala.util.continuations._
    
    object ContinuationsExample extends App {
      val widget1 = Widget()
      val widget2 = Widget()
    
      reset {
        val event1 = widget1.getEvent
        println("Handling first event: " + event1)
        val event2 = widget2.getEvent
        println("Handling second event: " + event2)
      }
    
      widget2 fireEvent Event("should not be handled")
      widget1 fireEvent Event("event for first widget")
      widget2 fireEvent Event("event for second widget")
      widget1 fireEvent Event("one more event")
    }
    
    case class Event(text: String)
    
    case class Widget() {
      type Listener = Event => Unit
      var listeners : List[Listener] = Nil
    
      def getEvent = shift { (l: Listener) =>
        listeners = l +: listeners
      }
    
      def fireEvent(event: Event) = listeners.foreach(_(event))
    }
    

    This code actually compiles and runs, so you can try it yourself. You should receive following output:

    Handling first event: Event(event for first widget)
    Handling second event: Event(event for second widget)
    Handling first event: Event(one more event) 
    

    If you will compile this example, then don't forget to enable continuations by providing -P:continuations:enable argument for the Scala compiler.