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)
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.
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