I’ve landed on this thread many, many times so I’ll just paste my modified solution here. The above version was not general enough for me, since I wanted to get the container of an arbitrary user-defined type, not just AbstractArray
s.
I don’t remember where I saw this recursive solution originally (I think maybe the Julia docs, evolved from this post?), but here is the code I’ve been using, with some modifications to make it instantaneous
function _container_type(T::Type)
isa(T, UnionAll) && return _container_type(T.body)
return T.name.wrapper
end
@generated function container_type(::Type{T}) where {T}
container = _container_type(T)
return :($container)
end
The reason it’s inside a @generated
is just for caching. You can’t do (::Type{T}) where {T}
in the _container_type
because Julia will hit a stack overflow.
With this, you can get the container for arbitrary types, with no runtime cost:
julia> container_type(AbstractArray)
AbstractArray
julia> container_type(AbstractArray{Float64,3})
AbstractArray
julia> struct F{T1,T2,T3}
x::T1
y::T2
z::T3
end
julia> container_type(F{Float64,String,Tuple{Float64,Float32}})
F
julia> @btime container_type(F{Float64,String})
0.875 ns (0 allocations: 0 bytes)
F
However, this will breaks if there is some abstract type with more type parameters than the user-defined struct.