Invalid subtyping: can only subtype data types (related to symbolics too)

Edit: it was just a syntax error, that is being reported a bit misleadingly and led me astray

I was playing with defining convoluted types and stumbled upon this behavior:

julia> struct S{T} <: AbstractVector{T} where {T<:Integer} end
ERROR: invalid subtyping in definition of S: can only subtype data types.

I think it is happening because typeof(AbstractVector) == UnionAll instead of DataType. Could someone hand-hold me through an explanation of why this is forbidden? Not just the dry rule “can not subtype UnionAll”, but focusing more on the “why”, what becomes unwieldy and unpleasant for the dispatcher and compiler?

Edit: Another way to ask the question is what is the difference between the following two attempts that I initially thought are the same, but it seems only one of them works:

julia> struct S1{T <: Integer} <: AbstractVector{T} end
# works fine

julia> struct S2{T} <: AbstractVector{T} where {T <: Integer} end
ERROR: invalid subtyping in definition of S2: can only subtype data types.

As to why I was trying to do this, I describe it in the block below, but I suspect it is not important - I will figure out some other way to do it. It had to do with defining new Symbolic operators with Symbolics.jl. I am describing it here, because maybe the creators of Symbolics have faced similar issues.

Click to expand the initial reason I stumbled upon this

I wanted to define a bunch of symbolic objects that have mostly the same behaviors and interfaces and internal structure, but which print slightly differently. For example
struct SymbolicTensorProductOfKets <: Symbolic{Ket} terms end
and
struct SymbolicTensorProductOfOperators <: Symbolic{Operator} terms end
So I thought it would make sense to define
struct SymbolicTensorProduct{T} <: Symbolic{T} where {T <: Union{Ket,Operator}} terms end
but that does not work.

Perhaps you want:

struct S{T <: Integer} <: AbstractVector{T}
  x::Int
end
1 Like

I think you are right! It is not immediately clear to me why the two syntaxes are interpreted differently.

1 Like

There is another critical difference AbstractVector vs the concrete type Vector

1 Like

You are right, it needs to be AbstractVector. I edited the initial question. However, I do not think there is a clear answer yet. I still do not have much understanding of why the following two are different:

julia> struct S1{T <: Integer} <: AbstractVector{T} end
# works fine

julia> struct S2{T} <: AbstractVector{T} where {T <: Integer} end
ERROR: invalid subtyping in definition of S2: can only subtype data types.
1 Like

There’s no where clause in struct definition

1 Like

Oh, so it is just a syntax error!? That is fair, but the error message should have been one about a syntax error (using where with struct definitions), not an error about subtyping, right?

julia> struct S2{T} <: AbstractVector{T} where {T <: Integer} end
ERROR: invalid subtyping in definition of S2: can only subtype data types.

julia> struct S2{T} <: AbstractVector{T} end
# works fine

julia> struct S2{T} where {T<:Integer} end
ERROR: syntax: invalid type signature around ...