SlideShare a Scribd company logo
Functional Reactive Programming
  with Examples in Scala + GWT

                Sasha Kazachonak
                 kazachonak.com
Google Web Toolkit Tutorial
Scala + GWT. Part 1.
class StockWatcher extends EntryPoint {
   val stocksFlexTable = new FlexTable
   val stocks = new mutable.ArrayBuffer[String]()

  def onModuleLoad {
    stocksFlexTable.setText(0, 0, "Symbol")
    stocksFlexTable.setText(0, 1, "Price")
    stocksFlexTable.setText(0, 2, "Change")
    stocksFlexTable.setText(0, 3, "Remove")
  }
Scala + GWT. Part 2.
private def addStock(symbol: String) {
   if (stocks.contains(symbol))
      return

  val row = stocksFlexTable.getRowCount
  stocks += symbol
  stocksFlexTable.setText(row, 0, symbol)
  stocksFlexTable.setWidget(row, 2, new Label)

  val removeStockButton = new Button("x", new ClickHandler {
     def onClick(event: ClickEvent) = {
       val removedIndex = stocks.indexOf(symbol)
       stocks.remove(removedIndex)
       stocksFlexTable.removeRow(removedIndex + 1)
     }
  })
Scala + GWT. Part 3.
private def updateTable(prices: Array[StockPrice]) {
   prices.foreach(updateTable)
}


private def updateTable(price: StockPrice) {
   if (!stocks.contains(price.symbol)) {
      return
   }

   val row = stocks.indexOf(price.symbol) + 1

   stocksFlexTable.setText(row, 1, price.price)
   val changeWidget = stocksFlexTable.getWidget(row, 2).asInstanceOf
   [Label]
   changeWidget.setText(price.changePercent + "%")
github.com/kazachonak/contour
class StockWatcherView extends View {
   val widget =
      FlexTable(Stock.all)( stock => List(
        Column("Symbol")(Label(stock.symbol)),
        Column("Price")(Label(stock.price.toString)),
        Column("Change")(
           Label(stock.changePercent + "%")
        ),
        Column("Remove")(Button(Stock.all -= stock, "x"))
   ))
    private def addStock(symbol: String) {
      Stock.all += new Stock(symbol)
Good luck doing it in another language

●   No additional variables manipulation
●   Much cooler: FlexTable is not fully re-rendered. Just
    the required rows are updated.
●   Model-View synchronization is incapsulated in
    Reactive Collection implementation and View DSL
    implementation.
●   So it can be reused. No need to synchronize by hand.
●   All those abstractions are fully typesafe
    (indispensable when abstractions are non-trivial)
●   Implemented using only standard Scala language
    features without any magic.
The essence
of functional reactive programming

 is to specify the dynamic behavior of a value
 completely at the time of declaration.

                             Heinrich Apfelmus
                the author of the Haskell library
                               Reactive-banana
The basic ideas
●   Datatypes that represent a value "over time".
●   Computations that involve these changing-
    over-time values will themselves are values
    that change over time.

●   Imagine your program is a spreadsheet and all
    of your variables are cells. If any of the cells in
    a spreadsheet change, any cells that refer to
    that cell change as well.
The basic ideas. Example.
● You could represent the mouse coordinates as a pair of integer-over-time:
    x = mouse.x
    y = mouse.y
● We only need to make this assignment once, and the x and y variables will
  stay "up to date" automatically. No need to mutate variables.
● Computations based on result in values that change over time:
   minX = x – 16
  minY = y – 16
  maxX = x + 16
  maxY = y + 16
   minX will always be 16 less than the x coordinate of the mouse pointer.
● With reactive-aware libraries you could then say something like:
     rectangle(minX, minY, maxX, maxY)
     And a 32x32 box will be drawn around the mouse pointer and will track
   it. wherever it moves.
Deprecating the Observer Pattern
●   By Martin Odersky, Ingo Maier, Tiark Rompf
●   Published in 2010
●   Abstract:
    Programming interactive systems by means of the
    observer pattern is hard and error-prone yet is still
    the implementation standard in many production
    environments.
     We present an approach to gradually deprecate
    observers in favor of reactive programming
    abstractions…
Status quo
●   Growing number of non-expert computer users
●   Increasingly multimedia capable hardware
●   Increasing demand in interactive applications
●   Such apps require much efforts to deal with
    continuous user input and output
●   Programming models for user interfaces have not
    changed much
●   The predominant approach to deal with state
    changes in production software is still the
    observer pattern
Observers => Bugs
●   Quote from Adobe presentation from 2008:
    ●   1/3 of the code in Adobe’s desktop applications is devoted
        to event handling logic
    ●   1/2 of the bugs reported during a product cycle exist in
        this code
●   We claim that we can reduce event handling code by
    at least a factor of 3 once we replace publishers and
    observers with more appropriate abstractions.
●   The same abstractions should help us to reduce the
    bug ratio.
●   We believe that event handling code on average
    should be one of the least error-prone parts of an
    application.
Mouse Dragging Example
var path: Path = null
val moveObserver = { (event: MouseEvent) =>
  path.lineTo(event.position)
  draw(path)
}
control.addMouseDownObserver{ event =>
  path = new Path(event.position)
  control.addMouseMoveObserver(moveObserver)
}
control.addMouseUpObserver{ event =>
  control.removeMouseMoveObserver(moveObserver)
  path.close()
  draw(path)
The observer pattern violates
    many software engineering principles

●   Side-effects
●   Encapsulation
●   Composability
●   Separation of concerns
●   Scalablity
●   Uniformity
●   Abstraction
●   Resource management
●   Semantic distance
Let the tutorial begin
●   reactive-web.co.cc library written in Scala by
    Naftoli Gugenheim
●   I've modified it to make it work when
    compiled to JavaScript by Google Web Toolkit:
     github.com/kazachonak/reactive
EventStream
●   Similar to a collection of values, except that
    rather than all values existing simultaneously,
    each one exists at a different point in time.
●   Methods in reactive-core are named like the
    corresponding methods in the scala
    collections framework.
Creating an EventStream
val eventSource = new EventSource[String] {}
scheduleTask(10000) {
  eventSource.fire("Event after 10 seconds")
}

val eventStream: EventStream[String] =
  eventSource

val widgets =
List(Widgets.EventSourceInput(eventSource),
     Widgets.EventStreamOutput(eventStream))
Timer
class EventStream_Timer extends Demo {
  // Create a timer that fires every 2 seconds,
  // starting at 0, for 30 seconds
  private val timer = new Timer(0, 2000, {t => t
  >= 32000})

  val widgets =
    List(Widgets.EventStreamOutput(timer))
Adding listeners: foreach
val eventSource = new EventSource[String] {}

//The following is syntactic sugar for
// eventSource.foreach(event =>
// Window.alert("You fired: " + event))
for(event <- eventSource) {
   Window.alert("You fired: " + event)
}

val widgets = List(Widgets.EventSourceInput
(eventSource))
EventStream Transformations
●   Similar to how you can transform collections: List
    (1,2,3).map(_ * 10).filter(_ < 25).
●   Consumers of the resulting EventStream don't
    need to care about how it relates to the
    original EventStream.
●   Whenever the original EventStream fires an event,
    the transformed EventStreams may fire their own
    events that are based on the original's event,
    according to the transformation.
A more focused EventStream: filter
 val eventSource = new EventSource[String] {}

 // Only allow short events
 val eventStream =
      eventSource.filter(_.length < 5)

 val widgets =
 List(Widgets.EventSourceInput(eventSource),
    Widgets.EventStreamOutput
 (eventStream))
A transformed EventStream: map
val eventSource = new EventSource[String] {}

// Reverse the event
val eventStream = eventSource.map(_.reverse)

val widgets =
List(Widgets.EventSourceInput(eventSource),
   Widgets.EventStreamOutput(eventStream))
flatMap
  val original = List(1, 2, 3)

  val flatMapped = original.flatMap(x =>
    List(x*10, x*10+1, x*10+2))

  flatMapped ==
     List(10,11,12, 20,21,22, 30,31,32)

Similarly, flatMap allows you to create
  an EventStream that fires events that are fired by
  different other EventStreams.
Combining EventStreams: |
val allClicks = leftClicks | middleClicks | rightClicks
Signal
●   EventStream represents a stream of discrete
    values over time.
    In practice that means that you can never say
    "what is the current value?"
●   Signal represents a continuous value.
    In practical terms, a Signal has a current value,
    and an EventStream that, whenever the
    Signal's value changes, fires the new value.
Signal Examples.
 val myVal = Val(72)
val myVar = Var(31)
myVar.change.foreach(println)
myVar() = 29 // prints 29
Signal. map.
 val myVar = Var(3)
val mapped = myVar.map(_ * 10)
println(mapped.now) // prints 30
myVar() = 62
println(mapped.now) // prints 620
Signal. map.
val myVar = Var("This is a Var")

val mapped =
  myVar.map(s => "Reversed: "+s.reverse)

val widgets =
List(Widgets.VarInput(myVar),
   Widgets.SignalOutput(mapped))
Signal. flatMap.
  val myVar1 = Var(72)
val myVar2 = Var(69)
val myVar3 = Var(false)
val flatMapped = myVar3 flatMap {
   case true => myVar1
   case false => myVar2
}
println(flatMapped.now) // prints 69
myVar3() = true
println(flatMapped.now) // prints 72
myVar2() = 2
myVar1() = 1
println(flatMapped.now) // prints 1
myVar3() = false
Signal. flatMap.
def filteredList(filterSignal: Signal[String],
                   itemsSignal: Signal[List[String]]) =
  for {
     filter <- filterSignal
     items <- itemsSignal
  } yield items.filter(s => s.indexOf(filter) >= 0)
SeqSignal[T] extends Signal[Seq[T]]
 val bufferSignal = BufferSignal(1, 2, 3, 4, 5)

 bufferSignal.value += 6 // fires an Insert

 // fires a Remove and an Insert
 bufferSignal() = List(2, 3, 4, 5, 6, 7)
Stock.all is SeqSignal[Stock]
class StockWatcherView extends View {
   val widget =
      FlexTable(Stock.all)( stock => List(
        Column("Symbol")(Label(stock.symbol)),
        Column("Price")(Label(stock.price.toString)),
        Column("Change")(
           Label(stock.changePercent + "%")
        ),
        Column("Remove")(Button(Stock.all -= stock, "x"))
   ))
    private def addStock(symbol: String) {
      Stock.all += new Stock(symbol)
?

More Related Content

PDF
rx.js make async programming simpler
PDF
Rxjs kyivjs 2015
PDF
Qt Animation
PPTX
Pellucid stm
PDF
RxJS - The Reactive extensions for JavaScript
PDF
How to become an Android dev starting from iOS (and vice versa)
PDF
Hash map (java platform se 8 )
PPTX
Collection and framework
rx.js make async programming simpler
Rxjs kyivjs 2015
Qt Animation
Pellucid stm
RxJS - The Reactive extensions for JavaScript
How to become an Android dev starting from iOS (and vice versa)
Hash map (java platform se 8 )
Collection and framework

What's hot (20)

PDF
Cascadia.js: Don't Cross the Streams
PDF
Reactive data visualisations with Om
PDF
Interaksi obyek
PPT
6.1.1一步一步学repast代码解释
PDF
Petri Niemi Qt Advanced Part 1
PDF
Petri Niemi Qt Advanced Part 2
PDF
Real World Generics In Swift
PDF
Mini-lab 1: Stochastic Gradient Descent classifier, Optimizing Logistic Regre...
PDF
Jscex: Write Sexy JavaScript (中文)
PPT
Functional Programming Past Present Future
PPTX
กลุ่ม6
PDF
Map reduce: beyond word count
PDF
Harnessing the Power of Java 8 Streams
PDF
Practical Model View Programming
PDF
Jscex: Write Sexy JavaScript
PDF
Hw09 Hadoop + Clojure
PDF
Functional Javascript, CVjs
PDF
响应式编程及框架
PPT
Hill ch2ed3
PDF
Hadoop + Clojure
Cascadia.js: Don't Cross the Streams
Reactive data visualisations with Om
Interaksi obyek
6.1.1一步一步学repast代码解释
Petri Niemi Qt Advanced Part 1
Petri Niemi Qt Advanced Part 2
Real World Generics In Swift
Mini-lab 1: Stochastic Gradient Descent classifier, Optimizing Logistic Regre...
Jscex: Write Sexy JavaScript (中文)
Functional Programming Past Present Future
กลุ่ม6
Map reduce: beyond word count
Harnessing the Power of Java 8 Streams
Practical Model View Programming
Jscex: Write Sexy JavaScript
Hw09 Hadoop + Clojure
Functional Javascript, CVjs
响应式编程及框架
Hill ch2ed3
Hadoop + Clojure
Ad

Similar to Funtional Reactive Programming with Examples in Scala + GWT (20)

PDF
Functional Reactive Programming / Compositional Event Systems
PDF
Introduction To Functional Reactive Programming Poznan
PDF
Code europe
PDF
Reactive computing
PDF
Functional Reactive Programming in Clojurescript
PPT
Reactive programming with examples
PDF
Buy ebook Functional Reactive Programming 1st Edition Stephen Blackheath chea...
PDF
Reactive Collections
PDF
PDF
(Functional) reactive programming (@pavlobaron)
PDF
Effector: we need to go deeper
PDF
Tech fest
PDF
Reactive programming with RxJS - Taiwan
PDF
Coscup
PPTX
Reactive programming with rx java
PDF
Reactor 3.0, a reactive foundation for java 8 and Spring
PPTX
Reactive fsharp
PPTX
Reactive programming every day
PPTX
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Functional Reactive Programming / Compositional Event Systems
Introduction To Functional Reactive Programming Poznan
Code europe
Reactive computing
Functional Reactive Programming in Clojurescript
Reactive programming with examples
Buy ebook Functional Reactive Programming 1st Edition Stephen Blackheath chea...
Reactive Collections
(Functional) reactive programming (@pavlobaron)
Effector: we need to go deeper
Tech fest
Reactive programming with RxJS - Taiwan
Coscup
Reactive programming with rx java
Reactor 3.0, a reactive foundation for java 8 and Spring
Reactive fsharp
Reactive programming every day
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Ad

More from Vasil Remeniuk (20)

PPTX
Product Minsk - РТБ и Программатик
PDF
Работа с Akka Сluster, @afiskon, scalaby#14
PDF
Cake pattern. Presentation by Alex Famin at scalaby#14
PDF
Scala laboratory: Globus. iteration #3
PPTX
Testing in Scala by Adform research
PPTX
Spark Intro by Adform Research
PPTX
Types by Adform Research, Saulius Valatka
PPTX
Types by Adform Research
PPTX
Scalding by Adform Research, Alex Gryzlov
PPTX
Scalding by Adform Research, Alex Gryzlov
PPTX
Spark by Adform Research, Paulius
PPTX
Scala Style by Adform Research (Saulius Valatka)
PPTX
Spark intro by Adform Research
PPTX
SBT by Aform Research, Saulius Valatka
PDF
Scala laboratory: Globus. iteration #2
PPTX
Testing in Scala. Adform Research
PDF
Scala laboratory. Globus. iteration #1
PDF
Cassandra + Spark + Elk
PDF
Опыт использования Spark, Основано на реальных событиях
PDF
ETL со Spark
Product Minsk - РТБ и Программатик
Работа с Akka Сluster, @afiskon, scalaby#14
Cake pattern. Presentation by Alex Famin at scalaby#14
Scala laboratory: Globus. iteration #3
Testing in Scala by Adform research
Spark Intro by Adform Research
Types by Adform Research, Saulius Valatka
Types by Adform Research
Scalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex Gryzlov
Spark by Adform Research, Paulius
Scala Style by Adform Research (Saulius Valatka)
Spark intro by Adform Research
SBT by Aform Research, Saulius Valatka
Scala laboratory: Globus. iteration #2
Testing in Scala. Adform Research
Scala laboratory. Globus. iteration #1
Cassandra + Spark + Elk
Опыт использования Spark, Основано на реальных событиях
ETL со Spark

Funtional Reactive Programming with Examples in Scala + GWT

  • 1. Functional Reactive Programming with Examples in Scala + GWT Sasha Kazachonak kazachonak.com
  • 3. Scala + GWT. Part 1. class StockWatcher extends EntryPoint { val stocksFlexTable = new FlexTable val stocks = new mutable.ArrayBuffer[String]() def onModuleLoad { stocksFlexTable.setText(0, 0, "Symbol") stocksFlexTable.setText(0, 1, "Price") stocksFlexTable.setText(0, 2, "Change") stocksFlexTable.setText(0, 3, "Remove") }
  • 4. Scala + GWT. Part 2. private def addStock(symbol: String) { if (stocks.contains(symbol)) return val row = stocksFlexTable.getRowCount stocks += symbol stocksFlexTable.setText(row, 0, symbol) stocksFlexTable.setWidget(row, 2, new Label) val removeStockButton = new Button("x", new ClickHandler { def onClick(event: ClickEvent) = { val removedIndex = stocks.indexOf(symbol) stocks.remove(removedIndex) stocksFlexTable.removeRow(removedIndex + 1) } })
  • 5. Scala + GWT. Part 3. private def updateTable(prices: Array[StockPrice]) { prices.foreach(updateTable) } private def updateTable(price: StockPrice) { if (!stocks.contains(price.symbol)) { return } val row = stocks.indexOf(price.symbol) + 1 stocksFlexTable.setText(row, 1, price.price) val changeWidget = stocksFlexTable.getWidget(row, 2).asInstanceOf [Label] changeWidget.setText(price.changePercent + "%")
  • 6. github.com/kazachonak/contour class StockWatcherView extends View { val widget = FlexTable(Stock.all)( stock => List( Column("Symbol")(Label(stock.symbol)), Column("Price")(Label(stock.price.toString)), Column("Change")( Label(stock.changePercent + "%") ), Column("Remove")(Button(Stock.all -= stock, "x")) )) private def addStock(symbol: String) { Stock.all += new Stock(symbol)
  • 7. Good luck doing it in another language ● No additional variables manipulation ● Much cooler: FlexTable is not fully re-rendered. Just the required rows are updated. ● Model-View synchronization is incapsulated in Reactive Collection implementation and View DSL implementation. ● So it can be reused. No need to synchronize by hand. ● All those abstractions are fully typesafe (indispensable when abstractions are non-trivial) ● Implemented using only standard Scala language features without any magic.
  • 8. The essence of functional reactive programming is to specify the dynamic behavior of a value completely at the time of declaration. Heinrich Apfelmus the author of the Haskell library Reactive-banana
  • 9. The basic ideas ● Datatypes that represent a value "over time". ● Computations that involve these changing- over-time values will themselves are values that change over time. ● Imagine your program is a spreadsheet and all of your variables are cells. If any of the cells in a spreadsheet change, any cells that refer to that cell change as well.
  • 10. The basic ideas. Example. ● You could represent the mouse coordinates as a pair of integer-over-time: x = mouse.x y = mouse.y ● We only need to make this assignment once, and the x and y variables will stay "up to date" automatically. No need to mutate variables. ● Computations based on result in values that change over time: minX = x – 16 minY = y – 16 maxX = x + 16 maxY = y + 16 minX will always be 16 less than the x coordinate of the mouse pointer. ● With reactive-aware libraries you could then say something like: rectangle(minX, minY, maxX, maxY) And a 32x32 box will be drawn around the mouse pointer and will track it. wherever it moves.
  • 11. Deprecating the Observer Pattern ● By Martin Odersky, Ingo Maier, Tiark Rompf ● Published in 2010 ● Abstract: Programming interactive systems by means of the observer pattern is hard and error-prone yet is still the implementation standard in many production environments. We present an approach to gradually deprecate observers in favor of reactive programming abstractions…
  • 12. Status quo ● Growing number of non-expert computer users ● Increasingly multimedia capable hardware ● Increasing demand in interactive applications ● Such apps require much efforts to deal with continuous user input and output ● Programming models for user interfaces have not changed much ● The predominant approach to deal with state changes in production software is still the observer pattern
  • 13. Observers => Bugs ● Quote from Adobe presentation from 2008: ● 1/3 of the code in Adobe’s desktop applications is devoted to event handling logic ● 1/2 of the bugs reported during a product cycle exist in this code ● We claim that we can reduce event handling code by at least a factor of 3 once we replace publishers and observers with more appropriate abstractions. ● The same abstractions should help us to reduce the bug ratio. ● We believe that event handling code on average should be one of the least error-prone parts of an application.
  • 14. Mouse Dragging Example var path: Path = null val moveObserver = { (event: MouseEvent) => path.lineTo(event.position) draw(path) } control.addMouseDownObserver{ event => path = new Path(event.position) control.addMouseMoveObserver(moveObserver) } control.addMouseUpObserver{ event => control.removeMouseMoveObserver(moveObserver) path.close() draw(path)
  • 15. The observer pattern violates many software engineering principles ● Side-effects ● Encapsulation ● Composability ● Separation of concerns ● Scalablity ● Uniformity ● Abstraction ● Resource management ● Semantic distance
  • 16. Let the tutorial begin ● reactive-web.co.cc library written in Scala by Naftoli Gugenheim ● I've modified it to make it work when compiled to JavaScript by Google Web Toolkit: github.com/kazachonak/reactive
  • 17. EventStream ● Similar to a collection of values, except that rather than all values existing simultaneously, each one exists at a different point in time. ● Methods in reactive-core are named like the corresponding methods in the scala collections framework.
  • 18. Creating an EventStream val eventSource = new EventSource[String] {} scheduleTask(10000) { eventSource.fire("Event after 10 seconds") } val eventStream: EventStream[String] = eventSource val widgets = List(Widgets.EventSourceInput(eventSource), Widgets.EventStreamOutput(eventStream))
  • 19. Timer class EventStream_Timer extends Demo { // Create a timer that fires every 2 seconds, // starting at 0, for 30 seconds private val timer = new Timer(0, 2000, {t => t >= 32000}) val widgets = List(Widgets.EventStreamOutput(timer))
  • 20. Adding listeners: foreach val eventSource = new EventSource[String] {} //The following is syntactic sugar for // eventSource.foreach(event => // Window.alert("You fired: " + event)) for(event <- eventSource) { Window.alert("You fired: " + event) } val widgets = List(Widgets.EventSourceInput (eventSource))
  • 21. EventStream Transformations ● Similar to how you can transform collections: List (1,2,3).map(_ * 10).filter(_ < 25). ● Consumers of the resulting EventStream don't need to care about how it relates to the original EventStream. ● Whenever the original EventStream fires an event, the transformed EventStreams may fire their own events that are based on the original's event, according to the transformation.
  • 22. A more focused EventStream: filter val eventSource = new EventSource[String] {} // Only allow short events val eventStream = eventSource.filter(_.length < 5) val widgets = List(Widgets.EventSourceInput(eventSource), Widgets.EventStreamOutput (eventStream))
  • 23. A transformed EventStream: map val eventSource = new EventSource[String] {} // Reverse the event val eventStream = eventSource.map(_.reverse) val widgets = List(Widgets.EventSourceInput(eventSource), Widgets.EventStreamOutput(eventStream))
  • 24. flatMap val original = List(1, 2, 3) val flatMapped = original.flatMap(x => List(x*10, x*10+1, x*10+2)) flatMapped == List(10,11,12, 20,21,22, 30,31,32) Similarly, flatMap allows you to create an EventStream that fires events that are fired by different other EventStreams.
  • 25. Combining EventStreams: | val allClicks = leftClicks | middleClicks | rightClicks
  • 26. Signal ● EventStream represents a stream of discrete values over time. In practice that means that you can never say "what is the current value?" ● Signal represents a continuous value. In practical terms, a Signal has a current value, and an EventStream that, whenever the Signal's value changes, fires the new value.
  • 27. Signal Examples. val myVal = Val(72) val myVar = Var(31) myVar.change.foreach(println) myVar() = 29 // prints 29
  • 28. Signal. map. val myVar = Var(3) val mapped = myVar.map(_ * 10) println(mapped.now) // prints 30 myVar() = 62 println(mapped.now) // prints 620
  • 29. Signal. map. val myVar = Var("This is a Var") val mapped = myVar.map(s => "Reversed: "+s.reverse) val widgets = List(Widgets.VarInput(myVar), Widgets.SignalOutput(mapped))
  • 30. Signal. flatMap. val myVar1 = Var(72) val myVar2 = Var(69) val myVar3 = Var(false) val flatMapped = myVar3 flatMap { case true => myVar1 case false => myVar2 } println(flatMapped.now) // prints 69 myVar3() = true println(flatMapped.now) // prints 72 myVar2() = 2 myVar1() = 1 println(flatMapped.now) // prints 1 myVar3() = false
  • 31. Signal. flatMap. def filteredList(filterSignal: Signal[String], itemsSignal: Signal[List[String]]) = for { filter <- filterSignal items <- itemsSignal } yield items.filter(s => s.indexOf(filter) >= 0)
  • 32. SeqSignal[T] extends Signal[Seq[T]] val bufferSignal = BufferSignal(1, 2, 3, 4, 5) bufferSignal.value += 6 // fires an Insert // fires a Remove and an Insert bufferSignal() = List(2, 3, 4, 5, 6, 7)
  • 33. Stock.all is SeqSignal[Stock] class StockWatcherView extends View { val widget = FlexTable(Stock.all)( stock => List( Column("Symbol")(Label(stock.symbol)), Column("Price")(Label(stock.price.toString)), Column("Change")( Label(stock.changePercent + "%") ), Column("Remove")(Button(Stock.all -= stock, "x")) )) private def addStock(symbol: String) { Stock.all += new Stock(symbol)
  • 34. ?