Reactors

Programming Model for Composable Distributed Computing

Aleksandar Prokopec / @alexprokopec



Programs work with data.


def doc: List[String]


Programs use data to produce output.

def doc: List[String]
doc.foreach { s =>
  $("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
  $("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
  $("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
  $("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
  $("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
  $("#editor").append(s) }


Collections have high-level operations.

def time: Events[Int]

Event stream

def time: Events[Int]


time.onEvent { t =>
  doc.foreach { s =>
    $("#editor").append(s) }
}

Similarity


List

exists somewhere


Events

happens sometime

Equivalence


onEvent ~ foreach

time.onEvent(t => renderHtml())

Equivalence


Events.filter ~ List.filter

val frame: Events[Int] =
  time.filter(t % 16 == 0)

0, 1, 2, 3, ..., 16, 17, 18, ..., 32, ...
0             16           32

Equivalence


Events.map ~ List.map

val keys: Events[(Boolean, Char)]

val presses: Events[Char] =
  keys.filter(_._1).map(pc => pc._2)

When, exactly, is sometime?

As most UI toolkits,
event propagation is single-threaded.


Event streams are an abstraction for

asynchronous programming.


ASYNCHRONOUS


CONCURRENT

concurrent - occurring at the same time

asynchronous - not occurring at the same time



val frame =
  time.filter(_ % 16 == 0)
frame.onEvent(render)

Asynchronicity without concurrency is convenient.


Decouples components in the system, and prevents data races.



Concurrency is another useful property.

time.onEvent(render)
Reactor {
  time.onEvent(render)
}
Reactor {
  time.onEvent(render)
  keys.map(_._2).onEvent(update)
}
Reactor {
  time.onEvent(render)
  keys.map(_._2).onEvent(update)
}
Reactor {
  time.onEvent(render)
  keys.map(_._2).onEvent(update)
}
Reactor {
  time.onEvent(render)
  keys.map(_._2).onEvent(update)
}
Reactor {
  time.onEvent(render)
  keys.map(_._2).onEvent(update)
}
val server:
  Channel[(Id, Channel[List[String]])]

val (updates, updatechan) = open[List[String]]
updates.onEvent { newDoc =>
  doc = newDoc
}
server ! (docId, updatechan)

Broadcast


Communication pattern in which the sender sends the same message to multiple targets.



However, broadcast does not guarantee too much ordering.


Operations must be commutative.



insert((i1, x1), insert((i0, x0), doc))

=

insert((i0, x0), insert((i1, x1), doc))

Observation


An insert by process X has a UID that ends with X.



Why CRDT?


Online collaborative editor prototype in 50 minutes.





CRDT is a function.




import replication.crdt



Thank you!



http://github.com/reactors-io/reactors