Can a struct have a variable supertype?

I’m working on beefing up JavaCall.jl and I have a proxy struct (currently called JProxy) that represents a Java object, along with an abstract type hierarchy with one type for each Java type. It would be convenient if the JProxy struct had a variable supertype. Julia lets me do that but doesn’t behave in the way I expect. Here is an example:

abstract type A end
abstract type B <: A end

struct S{T} <: T where {T <: A} end

@show(S{A} <: A)
@show(S{B} <: A)
@show(S{B} <: B)

The @show calls output this:

S{A} <: A = true
S{B} <: A = true
S{B} <: B = false

I expected the last expression to return true but it returned false.

The struct declaration’s AST seems to tell a different story from what I expected:

:(struct S{T} <: T where {T <: A} end)

outputs

:(struct S{T} <: (T where T <: A)
      #= REPL[22]:1 =#
  end)

Which makes it look like there is actually a separate T variable for the supertype. Is this true? It seems like if it is then the variable is unbindable and is actually equivalent to A.

Yes, your analysis is correct. You can also check this be re-writing it

struct S{T} <: U where {U <: A} end

which behaves identically to your example. You’d want something like:

julia> struct (MT{T} <: T) where {T <: A} end
ERROR: syntax: invalid type signature

but that does not work, not this

julia> struct S{T<:A} <: T end
ERROR: invalid subtyping in definition of S

Anyway, bottom line is that you can’t do this. But you can just dispatch on the type parameter, so I don’t think S needs to have the same supertype as its type parameter.

1 Like