Type definition

type
parametric-types

#1

I’m trying to express a type where the field container types are all identical, but their element type varies. I have tried a few things but can’t crack it:

julia> struct MyType1{V <: AbstractVector}
          a::V{Int64}
          b::V{Float64}
      end
ERROR: TypeError: in Type{...} expression, expected UnionAll, got TypeVar

julia> struct MyType8{FV<:V{Float64}, IV <: V{Int64} where V <: AbstractVector}
           a::IV
           b::FV
       end
ERROR: UndefVarError: V not defined

Some help would be great please! - assuming this is possible to express at all.


#2

I don’t think this is possible in Julia. You can, however, always check some condition on the type parameters inside an inner constructor. Or you can just leave FV and IV as potentially different kinds of AbstractArray. Perhaps it’s worth considering why you need them to actually be instances of the same parametric type V? For example, would it be enough to just check that they have the same axes or indices inside the inner constructor?


#3

Yeah I don’t think so either.

For fun, I tried the following. So you want:

  1. V <: AbstractVector
  2. IV <: AbstractVector{Int}
  3. IV <: V
  4. FV <: AbstractVector{Float64}
  5. FV <: V

(You probably also want IV and FV to be concrete types, but that’s another problem.) Unfortunately, you can only place constraints on a type parameter when you define it. But I thought maybe you could introduce ‘slack’ type variables IS and FS, drop constraints 3 and 5, and instead add IV <: IS <: V and FV <: FS <: V, as in:

struct MyType8{V<:AbstractVector, IV<:AbstractVector{Int}, FV<:AbstractVector{Float64}, IV<:IS<:V, FV<:FS<:V}
    a::IV
    b::FV
end

But you can’t actually construct this type, I believe, since even with this simpler version:

struct Foo{L, U, L<:T<:U}
end

Calling Foo{Union{}, Any, Vector{Float64}}() results in

UndefVarError: T not defined

even though Union{} <: Vector{Float64} <: Any.


#4

Thanks both, makes sense.

The motivation was really just convenience. In reality, there are a dozen or so fields, all vectors of a few handful of element types. The structs would be created in a few ways, some of them coming from copied arrays (V == Vector), some of them coming from views (V == SubArray{...}) + some maybe whacky ReinterpretedArrays etc. I didn’t want to sacrifice later performance by unifying them all to AbstractVector. Without being able to do what we discussed above, the alternative is to just have a type parameter per field, or at least per element type. Slightly longer to write - that is all.