Stream: helpdesk (published)

Topic: container-of-container-of-consistent abstract type members


view this post on Zulip Eugene Shvarts (Nov 18 2022 at 19:15):

Suppose I have an abstract type A, and a handful of concrete types B<:A , C<:A, etc.. What would be the appropriate way to specify a type Vector{ Union{ Vector{B}, Vector{C}, ...} } ? Vector{Vector{A}}, Vector{Vector{<:A}}, and Vector{<:Vector{A}} all allow the inner containers to take varied input (e.g., [B(), C()]), but I want to exclude these at minimum for performance reasons, and so only allow a situation like [ [B(), B()], [C(), C()] ]

view this post on Zulip Syx Pek (Nov 18 2022 at 19:20):

julia> S = Vector{Union{Vector{Int}, Vector{Float64}}}()
Union{Vector{Float64}, Vector{Int64}}[]

julia> push!(S, [1,1,1])
1-element Vector{Union{Vector{Float64}, Vector{Int64}}}:
 [1, 1, 1]

julia> push!(S, [1.,1.,1.])
2-element Vector{Union{Vector{Float64}, Vector{Int64}}}:
 [1, 1, 1]
 [1.0, 1.0, 1.0]

julia> push!(S, Union{Int, Float64}[1.,1.,1])
ERROR: MethodError:  ...

view this post on Zulip Eugene Shvarts (Nov 18 2022 at 19:23):

@Syx Pek Yes exactly! Is there a way to specify the Union in the language of subtypes, so that I can instantiate more concrete types D<:A, E<:A, etc. and they slot in seamlessly?

view this post on Zulip Syx Pek (Nov 18 2022 at 19:33):

julia> function insert_special(x::Vector{T}) where T <: Number
           isconcretetype(T) || error("$T is not a concrete type")
           push!(get!(S, T, Vector{T}[]), x)
       end
insert_special (generic function with 1 method)

julia> S = Dict(Int => [[1,2,3], [4,5,6]], Float64 => [[1., 2., 3.]])
Dict{DataType, Vector} with 2 entries:
  Float64 => [[1.0, 2.0, 3.0]]
  Int64   => [[1, 2, 3], [4, 5, 6]]

julia> insert_special([1,2,3//2])
1-element Vector{Vector{Rational{Int64}}}:
 [1//1, 2//1, 3//2]

julia> insert_special(Union{Int, Float64}[1,2,3.])
ERROR: Union{Float64, Int64} is not a concrete type
Stacktrace: ...

julia> for (_, val) in S, vec in val # Recovering the elements
           println(vec)
       end
[1.0, 2.0, 3.0]
[1, 2, 3]
[4, 5, 6]
Rational{Int64}[1//1, 2//1, 3//2]

This works if order doesn't matter. In general, we can allow the struct to be free, but check our vectors during insertion. (One doesn't need a dictionary here)

view this post on Zulip Eugene Shvarts (Nov 18 2022 at 20:10):

@Syx Pek awesome, that makes a ton of sense. Thank you!


Last updated: Oct 02 2023 at 04:34 UTC