Skip to content

Instantly share code, notes, and snippets.

@adam-nathan
Created May 3, 2021 07:25
Show Gist options
  • Save adam-nathan/ca9d855013051c3d4de729633d359623 to your computer and use it in GitHub Desktop.
Save adam-nathan/ca9d855013051c3d4de729633d359623 to your computer and use it in GitHub Desktop.
Reactive programming in Scala (taken from Functional Program Design in Scala week 4 @ Coursera)
import scala.util.DynamicVariable
class Signal[T](expr: => T) {
import Signal._
private var myExpr: () => T = _
private var myValue: T = _
private var observers: Set[Signal[_]] = Set()
private var observed: List[Signal[_]] = Nil
update(expr)
protected def computeValue(): Unit = {
for (sig <- observed)
sig.observers -= this
observed = Nil
val newValue = caller.withValue(this)(myExpr())
/* Disable the following "optimization" for the assignment, because we
* want to be able to track the actual dependency graph in the tests.
*/
//if (myValue != newValue) {
myValue = newValue
val obs = observers
observers = Set()
obs.foreach(_.computeValue())
//}
}
protected def update(expr: => T): Unit = {
myExpr = () => expr
computeValue()
}
def apply() = {
observers += caller.value
assert(!caller.value.observers.contains(this), "cyclic signal definition")
caller.value.observed ::= this
myValue
}
}
class Var[T](expr: => T) extends Signal[T](expr) {
override def update(expr: => T): Unit = super.update(expr)
}
object Var {
def apply[T](expr: => T) = new Var(expr)
}
object NoSignal extends Signal[Nothing](???) {
override def computeValue() = ()
}
object Signal {
val caller = new DynamicVariable[Signal[_]](NoSignal)
def apply[T](expr: => T) = new Signal(expr)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment