Observables

Observables

Observables are like Refs but you can listen to changes.

julia> using Interact

julia> observable = Observable(0)
Observable{Int64} with 0 listeners. Value:
0

julia> h = on(observable) do val
           println("Got an update: ", val)
       end
#1 (generic function with 1 method)

julia> observable[] = 42
Got an update: 42
42

To get the value of an observable index it with no arguments

julia> observable[]
42

To remove a handler use off with the return value of on:

julia> off(observable, h)

How is it different from Reactive.jl?

The main difference is Signals are manipulated mostly by converting one signal to another. For example, with signals, you can construct a changing UI by creating a Signal of UI objects and rendering them as the signal changes. On the other hand, you can use an Observable both as an input and an output. You can arbitrarily attach outputs to inputs allowing structuring code in a signals-and-slots kind of pattern.

Another difference is Observables are synchronous, Signals are asynchronous. Observables may be better suited for an imperative style of programming.

API

Type

Like a Ref but updates can be watched by adding a handler using on.

Functions

Observables.onMethod.
on(f, o::AbstractObservable)

Adds function f as listener to o. Whenever o's value is set via o[] = val f is called with val.

Observables.offMethod.
off(o::AbstractObservable, f)

Removes f from listeners of o.

Base.setindex!Method.
o[] = val

Updates the value of an Observable to val and call its listeners.

Base.getindexMethod.
o[]

Returns the current value of o.

Observables.onanyMethod.
onany(f, args...)

Calls f on updates to any oservable refs in args. args may contain any number of Observable ojects. f will be passed the values contained in the refs as the respective argument. All other ojects in args are passed as-is.

Base.map!Method.
map!(f, o::Observable, args...)

Updates o with the result of calling f with values extracted from args. args may contain any number of Observable ojects. f will be passed the values contained in the refs as the respective argument. All other ojects in args are passed as-is.

connect!(o1::Observable, o2::Observable)

Forward all updates to o1 to o2

Base.mapMethod.
map(f, o::Observable, args...)

Creates a new oservable ref which contains the result of f applied to values extracted from args. The second argument o must be an oservable ref for dispatch reasons. args may contain any number of Observable ojects. f will be passed the values contained in the refs as the respective argument. All other ojects in args are passed as-is.

throttle(dt, input::AbstractObservable)

Throttle a signal to update at most once every dt seconds. The throttled signal holds the last update of the input signal during each dt second time window.

Macros

Observables.@mapMacro.

@map(expr)

Wrap AbstractObservables in & to compute expression expr using their value. The expression will be computed when @map is called and every time the AbstractObservables are updated.

Examples

julia> a = Observable(2);

julia> b = Observable(3);

julia> c = Observables.@map &a + &b;

julia> c[]
5

julia> a[] = 100
100

julia> c[]
103

@map!(d, expr)

Wrap AbstractObservables in & to compute expression expr using their value: the expression will be computed every time the AbstractObservables are updated and d will be set to match that value.

Examples

julia> a = Observable(2);

julia> b = Observable(3);

julia> c = Observable(10);

julia> Observables.@map! c &a + &b;

julia> c[]
10

julia> a[] = 100
100

julia> c[]
103
Observables.@onMacro.

@on(expr)

Wrap AbstractObservables in & to execute expression expr using their value. The expression will be computed every time the AbstractObservables are updated.

Examples

julia> a = Observable(2);

julia> b = Observable(3);

julia> Observables.@on println("The sum of a+b is $(&a + &b)");

julia> a[] = 100;
The sum of a+b is 103