Skip to content

Instantly share code, notes, and snippets.

@adamgfraser
Created May 6, 2018 10:21
Show Gist options
  • Save adamgfraser/20d40b3dca6a122f7eca3df2fec6981a to your computer and use it in GitHub Desktop.
Save adamgfraser/20d40b3dca6a122f7eca3df2fec6981a to your computer and use it in GitHub Desktop.
object Reactive {
type Signaled[T] = implicit Signal[_] => T
class Signal[T](expr: Signaled[T]) {
private var myExpr: () => T = _
private var myValue: T = _
private var observers: Set[Signal[_]] = Set()
update(expr)
protected def update(expr: Signaled[T]): Unit = {
myExpr = () => expr(this)
computeValue()
}
protected def computeValue(): Unit = {
val newValue = myExpr()
if (myValue != newValue) {
myValue = newValue
val obs = observers
observers = Set()
obs.foreach(_.computeValue())
}
}
def apply()(implicit caller: Signal[_] = NoSignal): T = {
observers += caller
assert(!caller.observers.contains(this), "cyclic signal definition")
myValue
}
}
object NoSignal extends Signal(???) {
override def computeValue() = ()
}
object Signal {
def apply[T](expr: Signaled[T]): Signal[T] = new Signal(expr)
}
class Var[T](expr: Signaled[T]) extends Signal(expr) {
override def update(expr: Signaled[T]): Unit = super.update(expr)
}
object Var {
def apply[T](expr: Signaled[T]): Var[T] = new Var(expr)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment