-
Notifications
You must be signed in to change notification settings - Fork 8
Open
Description
I am trying to implement a basic signal-style reactivity (e.g. SolidJS) with Julia and WebAssemblyCompiler.jl
TLDR
Why is this function not compiling?
function create_signal(initial_value)
return Signal(initial_value, Function[])
end
function create_counter_signal()
return create_signal(0)
end
compile(
(create_counter_signal,),
filepath = "counter/counter.wasm",
validate = true
)Details
This is the signal which works as expected in pure Julia:
begin
mutable struct Signal{T}
_value::T
subscribers::Vector{Function}
end
function Base.getproperty(s::Signal, name::Symbol)
if name === :value
return getfield(s, :_value)
else
return getfield(s, name)
end
end
function Base.setproperty!(s::Signal, name::Symbol, value)
if name === :value
setfield!(s, :_value, value)
notify(s)
else
setfield!(s, name, value)
end
end
end
function notify(s::Signal)
for subscriber in s.subscribers
subscriber(s._value)
end
end
function subscribe(s::Signal, subscriber::Function)
push!(s.subscribers, subscriber)
end
function create_signal(initial_value)
return Signal(initial_value, Function[])
end
md"""
This example demonstrates the reactivity of the signal. Whenever the value of my_signal is updated, the subscribed function is automatically called, printing the updated value. This showcases how the signal can be used to trigger reactions and update values in a reactive manner.
You can extend this example further by creating more complex subscribers or using the signal values to perform specific actions or update other parts of your Julia program.
"""
begin
my_signal = create_signal("")
subscribe(my_signal, x -> println("Value changed to: $x"))
my_signal.value = "Hello, World!"
my_signal.value = "Signals are reactive!"
my_signal.value = "Updating the value again..."
endWhich outputs:
Value changed to: Hello, World!
Value changed to: Signals are reactive!
Value changed to: Updating the value again...
Now, I want to create a simple Counter App using this but I am having trouble compiling one of the functions. Here is the full code:
begin
mutable struct Signal{T}
_value::T
subscribers::Vector{Function}
end
function Base.getproperty(s::Signal, name::Symbol)
if name === :value
return getfield(s, :_value)
else
return getfield(s, name)
end
end
function Base.setproperty!(s::Signal, name::Symbol, value)
if name === :value
setfield!(s, :_value, value)
notify(s)
else
setfield!(s, name, value)
end
end
end
function notify(s::Signal)
for subscriber in s.subscribers
subscriber(s._value)
end
end
function subscribe(s::Signal, subscriber::Function)
push!(s.subscribers, subscriber)
end
function create_signal(initial_value)
return Signal(initial_value, Function[])
end
function create_counter_signal()
return create_signal(0)
end
function increment(count_signal::Signal{Int})
count_signal.value += 1
update_signal(count_signal)
nothing
end
function update_signal(count_signal::Signal{Int})
@jscall(
"(id, src)=> document.getElementById(id).innerHTML=src",
Nothing,
Tuple{Externref,Externref},
JS.object("counter"),
"""<p>Count: $(count_signal.value)</p>"""
)
nothing
end
compile(
(create_counter_signal,),
(increment, Signal{Int}),
(update_signal, Signal{Int}),
filepath = "counter/counter.wasm",
validate = true
)And specifically this line (create_counter_signal,), inside of the compile block errors like so:
MethodError: no constructors have been defined for Function
Stack trace
Here is what happened, the most recent locations are first:
default(::Type{Function}) @ utils.jl:282
(::WebAssemblyCompiler.var"#84#181"{WebAssemblyCompiler.CompilerContext, Int64})(args::Vector{Any}) @ compile_block.jl:521
matchforeigncall(fun::WebAssemblyCompiler.var"#84#181"{WebAssemblyCompiler.CompilerContext, Int64}, node::Expr, sym::Symbol) @ utils.jl:88
compile_block(ctx::WebAssemblyCompiler.CompilerContext, cfg::Core.Compiler.CFG, phis::Dict{Int64, Any}, idx::Int64) @ compile_block.jl:517
(::WebAssemblyCompiler.var"#283#284"{WebAssemblyCompiler.CompilerContext, Dict{Int64, Any}, Ptr{WebAssemblyCompiler.LibBinaryen.Relooper}, Core.Compiler.CFG})(idx::Int64) @
iterate(::Base.Generator{Base.OneTo{Int64}, WebAssemblyCompiler.var"#283#284"{WebAssemblyCompiler.CompilerContext, Dict{Int64, Any}, Ptr{WebAssemblyCompiler.LibBinaryen.Relooper}, Core.Compiler.CFG}}) @ [generator.jl:47](https://github.com/JuliaLang/julia/tree/48d4fd48430af58502699fdf3504b90589df3852/base/generator.jl#L42)
collect(itr::Base.Generator{Base.OneTo{Int64}, WebAssemblyCompiler.var"#283#284"{WebAssemblyCompiler.CompilerContext, Dict{Int64, Any}, Ptr{WebAssemblyCompiler.LibBinaryen.Relooper}, Core.Compiler.CFG}}) @ [array.jl:834](https://github.com/JuliaLang/julia/tree/48d4fd48430af58502699fdf3504b90589df3852/base/array.jl#L827)
compile_method_body(ctx::WebAssemblyCompiler.CompilerContext) @ compiler.jl:145
compile_method(ctx::WebAssemblyCompiler.CompilerContext, funname::String; sig::Type, exported::Bool) @ compiler.jl:101
compile(::Tuple{typeof(Main.var"workspace#138".create_counter_signal)}, ::Vararg{Tuple}; filepath::String, jspath::String, validate::Bool, optimize::Bool, experimental::Bool, names::Nothing) @ compiler.jl:58
[This cell: line 1](http://localhost:1234/edit?id=353ab39a-29d7-11ef-0548-6d249aabf9fe#03b24a0d-7512-4920-b2ac-14c8500c0299)
compile(
(create_counter_signal,),Metadata
Metadata
Assignees
Labels
No labels