Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Reqest] Static Observable graph #75

Open
SimonDanisch opened this issue Sep 4, 2021 · 3 comments
Open

[Feature Reqest] Static Observable graph #75

SimonDanisch opened this issue Sep 4, 2021 · 3 comments

Comments

@SimonDanisch
Copy link
Member

Just from a slack discussion with @mschauer, which hopelessly nerd-sniped me, since I've always wanted static, no overhead observable graphs as well...
A possible implementation could be this:

struct StaticObservable{T, Listeners} <: Observables.AbstractObservable
    listeners::Listeners
    value::Base.RefValue{T}
end

Base.getindex(obs::StaticObservable) = obs.value[]
Observables.listeners(obs::StaticObservable) = obs.listeners

_notify(val, funcs::Tuple{}) where F = nothing
function _notify(val, funcs::Tuple)
    f = first(funcs)
    f(val)
    _notify(val, Base.tail(funcs))
end

function Base.notify(obs::StaticObservable)
    val = observable[]
    _notify(val, obs.listeners)
    return
end

function Base.setindex!(observable::StaticObservable, val)
    observable.val[] = val
    notify(observable)
    return val
end

The question is how to construct the graph... Since the current API relies on lots of dynamic behavior, the normal API can't be used to construct the observables.

I had the idea to use static_obs = make_static(observables...), but the Observable api doesn't really allow to walk over the graph and convert the nodes to StaticObservable... So is the only way to use something like SoonToBeStaticObservable,
which works like Observable but keeps more information about the graph, and can then be converted via make_static to a static graph?

@mschauer
Copy link

mschauer commented Sep 9, 2021

As this is similar to https://github.com/tisztamo/FunctionWranglers.jl/blob/master/src/FunctionWranglers.jl let's ping @tisztamo . Maybe @tisztamo can also comment on the choice of "tuple type" or a recursive type for "listeners"

@mschauer
Copy link

mschauer commented Sep 9, 2021

Looks like _notify as proposed does the trick, just checking the time to update some Ref's with a handcrafted StaticObservable I get

  1.434 ns (0 allocations: 0 bytes) # Update 1 Ref
  3.859 ns (0 allocations: 0 bytes) # Update 8 Refs

compared to a ordinary observable updating a single listener

  34.075 ns (0 allocations: 0 bytes)

@tisztamo
Copy link

Yes, tail recursion on tuples and recursive types have similar characteristics(e.g.: https://discourse.julialang.org/t/automatically-fusing-together-several-for-loops/46097/17 ). Not sure if there is a difference in compile times though. I think that the the proposed solution is fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants