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

NamedTuple ERROR: Actor of type LoggerActor expects data to be of type #30

Closed
zsoerenm opened this issue Jul 11, 2023 · 2 comments
Closed
Assignees

Comments

@zsoerenm
Copy link
Contributor

MWE:

using Rocket
source = from([ 0, 1, 2 ])
result = source |> map(NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, val -> (value = val < 2 ? nothing : val, ))
subscribe!(result, logger())

Errors with:

ERROR: Actor of type LoggerActor{NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, Nothing} expects data to be of type NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, but data of type NamedTuple{(:value,), Tuple{Nothing}} has been found.
Stacktrace:
  [1] next!(actor::LoggerActor{NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, Nothing}, data::NamedTuple{(:value,), Tuple{Nothing}})
    @ Rocket ~/.julia/packages/Rocket/EGm1W/src/actor.jl:208
  [2] on_next!(actor::Rocket.MapActor{Int64, LoggerActor{NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, Nothing}, var"#19#20"}, data::Int64)
    @ Rocket ~/.julia/packages/Rocket/EGm1W/src/operators/map.jl:62
  [3] scheduled_next!
    @ ~/.julia/packages/Rocket/EGm1W/src/schedulers/asap.jl:23 [inlined]
  [4] next!
    @ ~/.julia/packages/Rocket/EGm1W/src/actor.jl:207 [inlined]
  [5] on_subscribe!(observable::ArrayObservable{Int64, AsapScheduler}, actor::Rocket.MapActor{Int64, LoggerActor{NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, Nothing}, var"#19#20"}, scheduler::AsapScheduler)
    @ Rocket ~/.julia/packages/Rocket/EGm1W/src/observable/array.jl:45
  [6] scheduled_subscription!
    @ ~/.julia/packages/Rocket/EGm1W/src/schedulers/asap.jl:21 [inlined]
  [7] subscribe!
    @ ~/.julia/packages/Rocket/EGm1W/src/utils.jl:110 [inlined]
  [8] on_subscribe!
    @ ~/.julia/packages/Rocket/EGm1W/src/observable/proxy.jl:103 [inlined]
  [9] subscribe!
    @ ~/.julia/packages/Rocket/EGm1W/src/utils.jl:108 [inlined]
 [10] check_on_subscribe_with_factory!
    @ ~/.julia/packages/Rocket/EGm1W/src/subscribable.jl:246 [inlined]
 [11] subscribe!(subscribable::ProxyObservable{NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, ArrayObservable{Int64, AsapScheduler}, Rocket.MapProxy{Int64, var"#19#20"}}, factory::Rocket.LoggerActorFactory{Nothing})
    @ Rocket ~/.julia/packages/Rocket/EGm1W/src/subscribable.jl:242
 [12] top-level scope
    @ REPL[18]:1
@bvdmitri
Copy link
Member

Thanks for your question!

This is an unfortunate consequence of how Julia's type inference work. In Rocket.jl the operator map(ExpectedType, MappingFn) expects that the MappingFn always returns an instance of type ExpectedType. However, in your case this property does not hold:

julia> val = 1
1

julia> data = (value = val < 2 ? nothing : val, )
(value = nothing,)

julia> typeof(data) isa NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}
false

This happens because Julia infers typeof(data) as NamedTuple{(:value,), Tuple{Nothing}} and this is not the same as NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}.

julia> NamedTuple{(:value,), Tuple{Nothing}} <: NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}
false

This has nothing really to do with the Rocket.jl library and relates to the type-inference machinery of the Julia programming language, but luckily you have at least two workarounds for this.

Workaround 1

Use the @NamedTuple macro explicitly to force Julia to use the ExpectedType as of following:

julia> result = source |> map(NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}, val -> @NamedTuple{value::Union{Nothing, Int64}}((val < 2 ? nothing : val, )))

julia> subscribe!(result, logger())
[LogActor] Data: NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}((nothing,))
[LogActor] Data: NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}((nothing,))
[LogActor] Data: NamedTuple{(:value,), Tuple{Union{Nothing, Int64}}}((2,))
[LogActor] Completed

The @NamedTuple macro exists precisely for this type of cases in the Julia language.

Workaround 2

Use Any as the ExpectedType. In this way you don't specify any constraints on the output type and it should not have any performance penalties unless you chain other operators after the map operator.

julia> result = source |> map(Any, val -> (value = val < 2 ? nothing : val, ))
ProxyObservable(Any, MapProxy(Int64))

julia> subscribe!(result, logger())
[LogActor] Data: (value = nothing,)
[LogActor] Data: (value = nothing,)
[LogActor] Data: (value = 2,)
[LogActor] Completed

@zsoerenm
Copy link
Contributor Author

Thanks, workaround 1 worked perfectly!

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

2 participants