So I started digging into the library. Here is cat_t from abstractarray.jl
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
catdims = dims2cat(dims)
shape = cat_size_shape(catdims, X...)
A = cat_similar(X[1], T, shape)
if count(!iszero, catdims)::Int > 1
fill!(A, zero(T))
end
return __cat(A, shape, catdims, X...)
end
It hints to
cat_similar(A, ::Type{T}, shape) where T = Array{T}(undef, shape)
cat_similar(A::AbstractArray, ::Type{T}, shape) where T = similar(A, T, shape)
So implementing similar (resolving some ambiguities) and setindex! we get
struct ConcreteVector{T} <: AbstractVector{T}
vector::Vector{T}
end
Base.size(v::ConcreteVector{T}) where T = size(v.vector)
Base.copy(v::ConcreteVector{T}) where T = ConcreteVector{T}(copy(v.vector))
Base.similar(v::ConcreteVector, ::Type{T}, dims::Tuple{Int64}) where T =
ConcreteVector{T}(Vector{T}(undef, dims[1]))
Base.push!(v::ConcreteVector{T}, t::T) where T = push!(v.vector, t)
Base.getindex(v::ConcreteVector{T}, i::Int) where T = getindex(v.vector, i)
Base.setindex!(v::ConcreteVector{T}, t::T, i::Int) where T = setindex!(v.vector, t, i)
Base.empty!(v::ConcreteVector{T}) where T = empty!(v.vector)
Base.iterate(v::ConcreteVector{T}, state) where T =
iterate(v.vector, state)
Base.iterate(v::ConcreteVector{T}) where T =
iterate(v.vector)
v = ConcreteVector{Int}(Vector{Int}())
push!(v, 1)
println(typeof(v))
v = vcat(v, 2)
println(typeof(v))
resulting in
ConcreteVector{Int64}
ConcreteVector{Int64}
So if noone has a better idea it seems stepping into the standard library is the way to go.