Though I thought I understood UnionAll types pretty well by now, some behavior of them are still hard to understand.
Consider the following example:
julia> struct MyType{N,S<:NTuple{N}}
t::S
end
MyType
has two type parameters N
and S
, where the latter depends on the former. I create instances of two different MyType
types—one with an Int64
tuple and another with a Float64
tuple—and store them in a vector:
julia> m1 = MyType{3,NTuple{3,Int64}}((1,2,3))
MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
julia> m2 = MyType{3,NTuple{3,Float64}}((1.0,2.0,3.0))
MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))
julia> v = [m1,m2]
2-element Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}:
MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))
And here goes some behavior that I don’t understand: why does the following generate an error:
julia> v::Vector{<:MyType{3}}
ERROR: TypeError: typeassert: expected Array{#s1,1} where #s1<:(MyType{3,S} where S<:(Tuple{T,T,T} where T)), got Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}
even though the following does not?
julia> v::Vector{<:(MyType{3,S} where {S})}
2-element Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}:
MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))
I find this strange because MyType{3}
in the failing example is also a UnionAll type that is not much different from MyType{3,S} where {S}
in the succeeding example:
julia> MyType{3}
MyType{3,S} where S<:(Tuple{T,T,T} where T)
Another strange behavior. v
is typed as
julia> typeof(v)
Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}
where the type parameter N
is not specified. However, because both entries of v
are MyType
with length-3 tuples, I thought we should be able to fix N
to 3 in the above type, but that was not the case:
julia> v::Array{MyType{3,S} where S<:(Tuple{Vararg{T,3}} where T),1}
ERROR: TypeError: typeassert: expected Array{MyType{3,S} where S<:(Tuple{Vararg{T,3}} where T),1}, got Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}
I wonder if somebody could explain these behaviors.
The main reason for asking this question: I had a custom type similar to MyType
, and wanted to create a function taking a vector similar to the above v
, but specifying the type of the function’s argument as ::AbstractVector{<:MyType{3}}
did not work because of the phenomenon described above.