Funtional Reactive Programming with Examples in Scala + GWT

34
Functional Reactive Programming with Examples in Scala + GWT Sasha Kazachonak kazachonak.com

description

Slides of the talk by Sasha Kazachonak on FRP, GWT and Scala at scalaby#10

Transcript of Funtional Reactive Programming with Examples in Scala + GWT

Page 1: Funtional Reactive Programming with Examples in Scala + GWT

Functional Reactive Programmingwith Examples in Scala + GWT

Sasha Kazachonak

kazachonak.com

Page 2: Funtional Reactive Programming with Examples in Scala + GWT

Google Web Toolkit Tutorial

Page 3: Funtional Reactive Programming with Examples in Scala + GWT

Scala + GWT. Part 1.

class StockWatcher extends EntryPoint {val stocksFlexTable = new FlexTableval 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")}

Page 4: Funtional Reactive Programming with Examples in Scala + GWT

Scala + GWT. Part 2.private def addStock(symbol: String) {

if (stocks.contains(symbol)) return

val row = stocksFlexTable.getRowCountstocks += symbolstocksFlexTable.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) }})

stocksFlexTable.setWidget(row, 3, removeStockButton);

}

Page 5: Funtional Reactive Programming with Examples in Scala + GWT

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 + "%")

}

Page 6: Funtional Reactive Programming with Examples in Scala + GWT

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

Page 7: Funtional Reactive Programming with Examples in Scala + GWT

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.

Page 8: Funtional Reactive Programming with Examples in Scala + GWT

The essence

of functional reactive programming

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

Heinrich Apfelmusthe author of the Haskell library

Reactive-banana

Page 9: Funtional Reactive Programming with Examples in Scala + GWT

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.

Page 10: Funtional Reactive Programming with Examples in Scala + GWT

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 – 16minY = y – 16maxX = x + 16maxY = 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.

Page 11: Funtional Reactive Programming with Examples in Scala + GWT

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…

Page 12: Funtional Reactive Programming with Examples in Scala + GWT

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

Page 13: Funtional Reactive Programming with Examples in Scala + GWT

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.

Page 14: Funtional Reactive Programming with Examples in Scala + GWT

Mouse Dragging Example

var path: Path = nullval 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)}

Page 15: Funtional Reactive Programming with Examples in Scala + GWT

The observer pattern violatesmany software engineering principles

● Side-effects● Encapsulation● Composability● Separation of concerns● Scalablity● Uniformity● Abstraction● Resource management● Semantic distance

Page 16: Funtional Reactive Programming with Examples in Scala + GWT

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

Page 17: Funtional Reactive Programming with Examples in Scala + GWT

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.

Page 18: Funtional Reactive Programming with Examples in Scala + GWT

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

Page 19: Funtional Reactive Programming with Examples in Scala + GWT

Timer

class EventStream_Timer extends Demo {// Create a timer that fires every 2 seconds,// starting at 0, for 30 secondsprivate val timer = new Timer(0, 2000, {t => t >= 32000})

val widgets = List(Widgets.EventStreamOutput(timer))

Page 20: Funtional Reactive Programming with Examples in Scala + GWT

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

Page 21: Funtional Reactive Programming with Examples in Scala + GWT

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.

Page 22: Funtional Reactive Programming with Examples in Scala + GWT

A more focused EventStream: filter

val eventSource = new EventSource[String] {}

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

val widgets =List(Widgets.EventSourceInput(eventSource), Widgets.EventStreamOutput(eventStream))

Page 23: Funtional Reactive Programming with Examples in Scala + GWT

A transformed EventStream: map

val eventSource = new EventSource[String] {}

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

val widgets =List(Widgets.EventSourceInput(eventSource), Widgets.EventStreamOutput(eventStream))

Page 24: Funtional Reactive Programming with Examples in Scala + GWT

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.

Page 25: Funtional Reactive Programming with Examples in Scala + GWT

Combining EventStreams: |

val allClicks = leftClicks | middleClicks | rightClicks

Page 26: Funtional Reactive Programming with Examples in Scala + GWT

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.

Page 27: Funtional Reactive Programming with Examples in Scala + GWT

Signal Examples.

val myVal = Val(72)val myVar = Var(31)myVar.change.foreach(println)myVar() = 29 // prints 29

Page 28: Funtional Reactive Programming with Examples in Scala + GWT

Signal. map.

val myVar = Var(3)val mapped = myVar.map(_ * 10)println(mapped.now) // prints 30myVar() = 62println(mapped.now) // prints 620

Page 29: Funtional Reactive Programming with Examples in Scala + GWT

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

Page 30: Funtional Reactive Programming with Examples in Scala + GWT

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 69myVar3() = trueprintln(flatMapped.now) // prints 72myVar2() = 2myVar1() = 1println(flatMapped.now) // prints 1myVar3() = falseprintln(flatMapped.now) // prints 2

Page 31: Funtional Reactive Programming with Examples in Scala + GWT

Signal. flatMap.

def filteredList(filterSignal: Signal[String], itemsSignal: Signal[List[String]]) =for { filter <- filterSignal items <- itemsSignal} yield items.filter(s => s.indexOf(filter) >= 0)

Page 32: Funtional Reactive Programming with Examples in Scala + GWT

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 InsertbufferSignal() = List(2, 3, 4, 5, 6, 7)

Page 33: Funtional Reactive Programming with Examples in Scala + GWT

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

Page 34: Funtional Reactive Programming with Examples in Scala + GWT

?