How do I put a parametrized struct into another parametrized container?

I think the problem happens inside this method. Specially, this line:

push!(nodes, MutableBinaryHeapNode(convert(T, v), i))

because what happens is basically the same as:

julia> struct Wrapper{T}; v :: T; end

julia> vec = Vector{Wrapper{Any}}()
0-element Array{Wrapper{Any},1}

julia> push!(vec, Wrapper(convert(Any, 10)))
ERROR: MethodError: Cannot `convert` an object of type 
  Wrapper{Int64} to an object of type 
  Wrapper{Any}
...

In other words, the push! wraps your value inside a wrapper struct (MutableBinaryHeapNode more specifically), the code expects that converting your value to the type of the heap (i.e., Any or SEvents) they will create a MutableBinaryHeapNode{Any} (or ...{SEvents}) and then push it into a vector. However, typeof(convert(Any, s_event_obj)) is typeof(s_event_obj) not Any, and therefore the object created is a MutableBinaryHeapNode{typeof(s_event_obj)} and not a MutableBinaryHeapNode{Any} and cannot be pushed into a Vector{MutableBinaryHeapNode{Any}} because it is the wrong type.

I see two workarounds (i.e., not considering a fix in their side):

  1. You need to use a concrete type instead of an abstract type. What would need you to STOP using a type that is different for each function inside it (i.e., not parametrized by closure). You would need to do:
struct SEvent
    callback::Function # or Any
    time::Float64
end
  1. (shameless self-promotion) Use my implementation of a MutableBinaryHeap, that I prefer to DataStructures.jl implementation. It is available in TrackingHeaps.jl (registered package, you can just add it). It is fully documented, and have come up recently in this thread.
3 Likes