Description of the reactive collections framework from the Scala 2014 workshop.
1Containers and Aggregates,Mutators and Isolatesfor Reactive ProgrammingAleksandar Prokopec, Philipp Haller, Martin Odersky
View Slide
Reactive Collectionshttp://reactive-collections.com2
Reactive3
4
5Observables (event streams)
6Observables (event streams)• declarativeval log = messages.filter(_.length < 100).scan(_ + “\n” + _)
7Observables (event streams)• declarativeval log = messages.filter(_.length < 100).scan(_ + “\n” + _)var log = “”def receive = {case s: String =>if (s.length < 100)log = log + “\n” + s}
8Actors• encapsulate mutable state
9Actors• encapsulate mutable statevar log = “”def receive = {case s: String =>if (s.length < 100)log = log + “\n” + s}
10Reactive collectionsIsolateReactiveChannelActor?ActorRef?ObservableObservable
11Reactive values
Reactive[T]12
val ticks: Reactive[Long]13ticks 1122334460606161
ticks onEvent { x =>log.debug(s”tick no.$x”)}141 2 3 4 60 61tick no.1tick no.2tick no.3tick no.4tick no.60tick no.61...
ticks foreach { x =>log.debug(s”tick no.$x”)}151 2 3 4 60 61
16for (x <- ticks) {log.debug(s”tick no.$x”)}Single-threaded!
17Reactive combinators
for (x <- ticks) yield {x / 60}18
val seconds: Reactive[Long] =for (x <- ticks) yield {x / 60}19
6061val seconds: Reactive[Long] =for (x <- ticks) yield {x / 60}20ticks 112233 60 61seconds0 0 0 1 1ticksseconds00011
val days: Reactive[Long] =seconds.map(_ / 86400)21
val days: Reactive[Long] =seconds.map(_ / 86400)val secondsToday =22
val days: Reactive[Long] =seconds.map(_ / 86400)val secondsToday =(seconds zip days) {(s, d) =>s – d * 86400}23
val angle =secondsInDay.map(angleFunc)24
val angle =secondsInDay.map(angleFunc)val light =secondsInDay.map(lightFunc)25
26
27val rotate =keysa ↓shift ↓ a ↑ shift ↑pgup ↓ pgup ↑keys
28val rotate =keys.filter(_ == PAGEUP)a ↓shift ↓ a ↑ shift ↑pgup ↓ pgup ↑keyspgup ↓ pgup ↑filter
29val rotate =keys.filter(_ == PAGEUP).map(_.down)a ↓shift ↓ a ↑ shift ↑pgup ↓ pgup ↑keyspgup ↓ pgup ↑filtertrue falsemap
30if (rotate()) viewAngle += 1true falsemap
31Signals
32trait Signal[T]extends Reactive[T] {def apply(): T}
33val rotate =keys.filter(_ == PAGEUP).map(_.down).signal(false)true falsemapsignal
34val rotate: Signal[Boolean] =keys.filter(_ == PAGEUP).map(_.down).signal(false)true falsemapsignal
35val rotate: Signal[Boolean]val ticks: Reactive[Long]ticks
36val rotate: Signal[Boolean]val ticks: Reactive[Long]ticksrotate
37val rotate: Signal[Boolean]val ticks: Reactive[Long]val viewAngle: Signal[Double] =ticksrotateviewAngle
38val rotate: Signal[Boolean]val ticks: Reactive[Long]val viewAngle: Signal[Double] =ticks.scanPast(0.0)ticksrotateviewAngle
39val rotate: Signal[Boolean]val ticks: Reactive[Long]val viewAngle: Signal[Double] =ticks.scanPast(0.0) {(a, _) =>if (rotate()) a + 1 else a}ticksrotateviewAngle
40
41val velocity =ticks.scanPast(0.0) {(v, _) =>}val viewAngle =
42val velocity =ticks.scanPast(0.0) {(v, _) =>if (rotate()) v + 1}val viewAngle =
43val velocity =ticks.scanPast(0.0) {(v, _) =>if (rotate()) v + 1else v – 0.5}val viewAngle =
44val velocity =ticks.scanPast(0.0) {(v, _) =>if (rotate()) v + 1else v – 0.5}val viewAngle =velocity.scanPast(0.0)(_ + _)
45
46Reactive mutators
47class Matrix {def apply(x: Int, y: Int): Doubledef update(x: Int, y: Int, v: Double)}
48val screenMat: Signal[Matrix] =(projMat zip viewMat)(_ * _)val invScreenMat =screenMat.map(_.inverse)
49Reactive[immutable.Matrix[T]]
50val screenMat: Signal[Matrix] =(projMat zip viewMat)(_ * _)val invScreenMat =screenMat.map(_.inverse)(4*4*8 + 16 + 16)*4*100 = 64 kb/s
51val screenMat = Mutable(new Matrix)(projMat, viewMat).mutate(screenMat) {(p, v) => screenMat().assignMul(p, v)}val invScreenMat = Mutable(new Matrix)screenMat.mutate(invScreenMat) {m => invScreenMat().assignInv(m)}
52Reactive collections
53
54val selected: Reactive[Set[Character]]
55val selected: ReactSet[Character]
56trait ReactSet[T]extends ReactContainer[T] {def apply(x: T): Boolean}
57trait ReactContainer[T] {def inserts: Reactive[T]def removes: Reactive[T]}
58A reactive collectionis a pairof reactive values
59val selected =new ReactHashSet[Character]
60
61val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c)))
62class ReactContainer[T] { self =>def inserts: Reactive[T]def removes: Reactive[T]def map[S](f: T => S) =new ReactContainer[S] {def inserts: Reactive[T] =self.inserts.map(f)def removes: Reactive[T] =self.removes.map(f)}}
63val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).to[ReactHashMap]
64val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).to[ReactHashMap]
65val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).to[ReactHashMap]
66val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).to[ReactHashMap]
67val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).react.to[ReactHashMap]
68val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).react.to[ReactHashMap]
69val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).react.to[ReactHashMap]
70val selected =new ReactHashSet[Character]val decorations = selected.map(c => (c, decoFor(c))).react.to[ReactHashMap]
71Isolates
72UI isolateclass UIextends Isolate[UI.Message] {val frames =source.filter(_ == UI.Frame)val exit = source onCase {case UI.Exit => exit()}}Source
73UI IsolateSourceAI IsolateSourceChannel[AI.Message] Channel[UI.Message]
74Reactive collectionsIsolateReactiveChannelActor?ActorRef?ObservableObservable
75Thank you!