Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reactive Collections

Reactive Collections

Description of the reactive collections framework from the Scala 2014 workshop.

Aleksandar Prokopec

July 30, 2014
Tweet

More Decks by Aleksandar Prokopec

Other Decks in Programming

Transcript

  1. 1
    Containers and Aggregates,
    Mutators and Isolates
    for Reactive Programming
    Aleksandar Prokopec, Philipp Haller, Martin Odersky

    View Slide

  2. Reactive Collections
    http://reactive-collections.com
    2

    View Slide

  3. Reactive
    3

    View Slide

  4. 4

    View Slide

  5. 5
    Observables (event streams)

    View Slide

  6. 6
    Observables (event streams)
    • declarative
    val log = messages
    .filter(_.length < 100)
    .scan(_ + “\n” + _)

    View Slide

  7. 7
    Observables (event streams)
    • declarative
    val log = messages
    .filter(_.length < 100)
    .scan(_ + “\n” + _)
    var log = “”
    def receive = {
    case s: String =>
    if (s.length < 100)
    log = log + “\n” + s
    }

    View Slide

  8. 8
    Actors
    • encapsulate mutable state

    View Slide

  9. 9
    Actors
    • encapsulate mutable state
    var log = “”
    def receive = {
    case s: String =>
    if (s.length < 100)
    log = log + “\n” + s
    }

    View Slide

  10. 10
    Reactive collections
    Isolate
    Reactive
    Channel
    Actor
    ?
    ActorRef
    ?
    Observable
    Observable

    View Slide

  11. 11
    Reactive values

    View Slide

  12. Reactive[T]
    12

    View Slide

  13. val ticks: Reactive[Long]
    13
    ticks 1
    1
    2
    2
    3
    3
    4
    4
    60
    60
    61
    61

    View Slide

  14. ticks onEvent { x =>
    log.debug(s”tick no.$x”)
    }
    14
    1 2 3 4 60 61
    tick no.1
    tick no.2
    tick no.3
    tick no.4
    tick no.60
    tick no.61
    ...

    View Slide

  15. ticks foreach { x =>
    log.debug(s”tick no.$x”)
    }
    15
    1 2 3 4 60 61

    View Slide

  16. 16
    for (x <- ticks) {
    log.debug(s”tick no.$x”)
    }
    Single-threaded!

    View Slide

  17. 17
    Reactive combinators

    View Slide

  18. for (x <- ticks) yield {
    x / 60
    }
    18

    View Slide

  19. val seconds: Reactive[Long] =
    for (x <- ticks) yield {
    x / 60
    }
    19

    View Slide

  20. 60
    61
    val seconds: Reactive[Long] =
    for (x <- ticks) yield {
    x / 60
    }
    20
    ticks 1
    1
    2
    2
    3
    3 60 61
    seconds
    0 0 0 1 1
    ticks
    seconds
    0
    0
    0
    1
    1

    View Slide

  21. val days: Reactive[Long] =
    seconds.map(_ / 86400)
    21

    View Slide

  22. val days: Reactive[Long] =
    seconds.map(_ / 86400)
    val secondsToday =
    22

    View Slide

  23. val days: Reactive[Long] =
    seconds.map(_ / 86400)
    val secondsToday =
    (seconds zip days) {
    (s, d) =>
    s – d * 86400
    }
    23

    View Slide

  24. val angle =
    secondsInDay.map(angleFunc)
    24

    View Slide

  25. val angle =
    secondsInDay.map(angleFunc)
    val light =
    secondsInDay.map(lightFunc)
    25

    View Slide

  26. 26

    View Slide

  27. 27
    val rotate =
    keys
    a ↓
    shift ↓ a ↑ shift ↑
    pgup ↓ pgup ↑
    keys

    View Slide

  28. 28
    val rotate =
    keys.filter(_ == PAGEUP)
    a ↓
    shift ↓ a ↑ shift ↑
    pgup ↓ pgup ↑
    keys
    pgup ↓ pgup ↑
    filter

    View Slide

  29. 29
    val rotate =
    keys.filter(_ == PAGEUP)
    .map(_.down)
    a ↓
    shift ↓ a ↑ shift ↑
    pgup ↓ pgup ↑
    keys
    pgup ↓ pgup ↑
    filter
    true false
    map

    View Slide

  30. 30
    if (rotate()) viewAngle += 1
    true false
    map

    View Slide

  31. 31
    Signals

    View Slide

  32. 32
    trait Signal[T]
    extends Reactive[T] {
    def apply(): T
    }

    View Slide

  33. 33
    val rotate =
    keys.filter(_ == PAGEUP)
    .map(_.down)
    .signal(false)
    true false
    map
    signal

    View Slide

  34. 34
    val rotate: Signal[Boolean] =
    keys.filter(_ == PAGEUP)
    .map(_.down)
    .signal(false)
    true false
    map
    signal

    View Slide

  35. 35
    val rotate: Signal[Boolean]
    val ticks: Reactive[Long]
    ticks

    View Slide

  36. 36
    val rotate: Signal[Boolean]
    val ticks: Reactive[Long]
    ticks
    rotate

    View Slide

  37. 37
    val rotate: Signal[Boolean]
    val ticks: Reactive[Long]
    val viewAngle: Signal[Double] =
    ticks
    rotate
    viewAngle

    View Slide

  38. 38
    val rotate: Signal[Boolean]
    val ticks: Reactive[Long]
    val viewAngle: Signal[Double] =
    ticks.scanPast(0.0)
    ticks
    rotate
    viewAngle

    View Slide

  39. 39
    val rotate: Signal[Boolean]
    val ticks: Reactive[Long]
    val viewAngle: Signal[Double] =
    ticks.scanPast(0.0) {
    (a, _) =>
    if (rotate()) a + 1 else a
    }
    ticks
    rotate
    viewAngle

    View Slide

  40. 40

    View Slide

  41. 41
    val velocity =
    ticks.scanPast(0.0) {
    (v, _) =>
    }
    val viewAngle =

    View Slide

  42. 42
    val velocity =
    ticks.scanPast(0.0) {
    (v, _) =>
    if (rotate()) v + 1
    }
    val viewAngle =

    View Slide

  43. 43
    val velocity =
    ticks.scanPast(0.0) {
    (v, _) =>
    if (rotate()) v + 1
    else v – 0.5
    }
    val viewAngle =

    View Slide

  44. 44
    val velocity =
    ticks.scanPast(0.0) {
    (v, _) =>
    if (rotate()) v + 1
    else v – 0.5
    }
    val viewAngle =
    velocity.scanPast(0.0)(_ + _)

    View Slide

  45. 45

    View Slide

  46. 46
    Reactive mutators

    View Slide

  47. 47
    class Matrix {
    def apply(x: Int, y: Int): Double
    def update(x: Int, y: Int, v: Double)
    }

    View Slide

  48. 48
    val screenMat: Signal[Matrix] =
    (projMat zip viewMat)(_ * _)
    val invScreenMat =
    screenMat.map(_.inverse)

    View Slide

  49. 49
    Reactive[immutable.Matrix[T]]

    View Slide

  50. 50
    val screenMat: Signal[Matrix] =
    (projMat zip viewMat)(_ * _)
    val invScreenMat =
    screenMat.map(_.inverse)
    (4*4*8 + 16 + 16)*4*100 = 64 kb/s

    View Slide

  51. 51
    val 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)
    }

    View Slide

  52. 52
    Reactive collections

    View Slide

  53. 53

    View Slide

  54. 54
    val selected: Reactive[Set[Character]]

    View Slide

  55. 55
    val selected: ReactSet[Character]

    View Slide

  56. 56
    trait ReactSet[T]
    extends ReactContainer[T] {
    def apply(x: T): Boolean
    }

    View Slide

  57. 57
    trait ReactContainer[T] {
    def inserts: Reactive[T]
    def removes: Reactive[T]
    }

    View Slide

  58. 58
    A reactive collection
    is a pair
    of reactive values

    View Slide

  59. 59
    val selected =
    new ReactHashSet[Character]

    View Slide

  60. 60

    View Slide

  61. 61
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))

    View Slide

  62. 62
    class 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)
    }
    }

    View Slide

  63. 63
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .to[ReactHashMap]

    View Slide

  64. 64
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .to[ReactHashMap]

    View Slide

  65. 65
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .to[ReactHashMap]

    View Slide

  66. 66
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .to[ReactHashMap]

    View Slide

  67. 67
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .react.to[ReactHashMap]

    View Slide

  68. 68
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .react.to[ReactHashMap]

    View Slide

  69. 69
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .react.to[ReactHashMap]

    View Slide

  70. 70
    val selected =
    new ReactHashSet[Character]
    val decorations = selected
    .map(c => (c, decoFor(c)))
    .react.to[ReactHashMap]

    View Slide

  71. 71
    Isolates

    View Slide

  72. 72
    UI isolate
    class UI
    extends Isolate[UI.Message] {
    val frames =
    source.filter(_ == UI.Frame)
    val exit = source onCase {
    case UI.Exit => exit()
    }
    }
    Source

    View Slide

  73. 73
    UI Isolate
    Source
    AI Isolate
    Source
    Channel[AI.Message] 
     Channel[UI.Message]

    View Slide

  74. 74
    Reactive collections
    Isolate
    Reactive
    Channel
    Actor
    ?
    ActorRef
    ?
    Observable
    Observable

    View Slide

  75. 75
    Thank you!

    View Slide