How to get the container type of a container?

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 AbstractArrays.

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.