A question on dispatch on type parameter being UnionAll

I’m a bit curious about the following problem, it’s not a big deal and has an easy solution, but anyway

struct A{T,S}
    t::T
    s::S
end

struct B{V<:A}
    v::Vector{V}
end

b1 = B([A(1,2), A(3,4.0)])  # element type is UnionAll
b2 = B([A(1,2), A(3,4)])    # element type is concrete

function f(b::B{T}) where {T}
    T isa UnionAll ? "UnionAll" : Symbol("not UnionAll")
end

The function f checks if the element type of b.v is a UnionAll, and takes different code paths.
Is there a way to handle this by dispatch instead of the isa test? I.e. have two methods for f with different signatures?
There’s of course this kludge:

g(b::B{T}) where {T} = g(b, typeof(T))
g(b::B, ::Type{UnionAll}) = "UnionAll"
g(b::B, ::Any) = Symbol("not UnionAll")

Both f and g are type stable, so things are handled at compile time, but in a bit non-julian fashion.

No you can’t dispatch on the type of a type in the same position as dispatching on the type itself.

Your solution with a second function is probably the neatest way if you really want to use dispatch, though if I were you I’d just branch like you did originally.

1 Like

Do you mean this?

v::Vector{Vector{Int64}} = [[1]]

function f_okay(v::Vector{T}) where T
    T
end
f_okay(v)

function f_no_support(v::Vector{T}) where T::Vector{<:Integer}
    T
end;
f_no_support(v)

No, if you look closely at the example:

julia> a = [A(1,2), A(3,4.0)]
2-element Vector{A{Int64}}:
 A{Int64, Int64}(1, 2)
 A{Int64, Float64}(3, 4.0)

The element type of a is A{Int64} which is an “incomplete” type, it’s really A{Int64, S} where S, with a free type variable S, i.e. a UnionAll type:

julia> typeof(eltype(a))
UnionAll

julia> dump(A{Int})
UnionAll
  var: TypeVar
    name: Symbol S
    lb: Union{}
    ub: abstract type Any
  body: struct A{Int64, S} <: Any
    t::Int64
    s::S

julia> dump(A{Int,S} where S)
UnionAll
  var: TypeVar
    name: Symbol S
    lb: Union{}
    ub: abstract type Any
  body: struct A{Int64, S} <: Any
    t::Int64
    s::S

And I wanted to know if this can be picked up by dispatch, something like

function f(b::B{T}) where {T isa UnionAll}  # unsupported
    ...
end

to distinguish it from when the element type (T) is e.g. A{Int, Int} or A{Int, Float64}, which is a “complete” DataType not a UnionAll.

1 Like