Define struct with two fields that have the same abstract type but different specialization

Let’s say I want to have a struct with two fields that both are arrays.
I want both array types to be the same e.g. Array, Array or CuArray, CuArray
But the specialization should be different like the first one holds float values and the second one integer values.

struct Foo{AC <: AbstractArray}
    float_array::AC{Float64}
    int_array::AC{Int}
end

Unfortunately, this throws an error:

ERROR: TypeError: in Type{...} expression, expected UnionAll, got a value of type TypeVar

Is that possible to be defined in the type or do I have to make both a subtype of AbstractArray and use inner constructors to force the same type?

1 Like

I think the only way is to declare two parameters:

struct Foo{ACF <: AbstractArray{Float64}, ACI <: AbstractArray{Int}}
    float_array::ACF
    int_array::ACI
end
4 Likes

This doesn’t meet my requirements, though. Your example would allow one to be a type of Array and the other could be a CuArray.

1 Like

As stated above, you will need two distinct type parameters for this. If you want to ensure they have the same outer type, consider validating that in an inner constructor.

3 Likes

You can’t put parameters in just the type part of a parametric type, only the parameter part or the whole thing; for example, Foo{Vector{Int}} is a valid type, but the implied Vector{Int}{Float64} isn’t. Also note that the direct supertype of a concrete type AC{Float64} is actually AbstractArray{Float64}. AC{T} where T is an iterated union of types, which like Unions is a way to group types into an ad-hoc supertype; AC{Int} and AC{Float64} are about as related to each other via AC as Int and Float64 are via Union{Int, Float64} or Any, which limits how we can define type parameters. Best I could do without constructor validation, and it’s not even close:

julia> struct Foo{AC<:AbstractArray, T<:AC, S<:AC}
           int_array::T
           float_array::S
       end

julia> Foo{Vector, Vector{Int}, Vector{Float64}}
Foo{Vector, Vector{Int64}, Vector{Float64}}

julia> Foo{AbstractVector{Int}, DenseVector{Int}, Vector{Int}} # horrible
Foo{AbstractVector{Int64}, DenseVector{Int64}, Vector{Int64}}
2 Likes