Is it possible to have a typevariable for an upperbound?

Just stumbled upon that I would like to transform a specific container to another specific container, and it looks like I have to take special care about Julia’s UnionAll types.
Concretely, I would like to map say Vector{<:Number} to MyVector{<:Number}.

What I thought could do the trick is a function like the following

f(::Type{Vector{<:T}}) where T = T

however

f(Vector{<:Number})

raises the error ERROR: UndefVarError: T not defined

Is something like this not supported in Julia? What could be a workaround?
thanks a lot

You’ll have to handle it specially, but see Base.parameter_upper_bound.

2 Likes

I build my own small solution to enable dispatch on UnionAll types.

first we need a little wrapper around TypeVariable which captures the bounds information in type-parameters

struct TV{LB, UB}
  lb::Type{LB}
  name::Symbol
  ub::Type{UB}
end
TV(tv::TypeVar) = TV(tv.lb, tv.name, tv.ub)
# for convenient syntax as upperbound is most often what you want to dispatch on
const TV′{UB, LB} = TV{LB, UB} 

Then 3 little functions do the trick to make the typeparameters available for dispatch on respective extra arguments to the function f

f(T::UnionAll) = _f(T, T.body, TV(T.var))
_f(T, S::UnionAll, vs...) = _f(T, S.body, vs..., TV(S.var))
_f(T, S::DataType, vs...) = f(T, vs...)

Now we can define dispatch rules like the following

f(::Type{<:Vector}, ::TV′{T}) where T <: Number = T
f(::Type{<:Vector}, ::TV) = true
f(::Type{<:Tuple}, ::TV′{Number}, ::TV′{AbstractString}) = "hi"

which indeed work like wanted

f(Vector{<:Number})  # Number
f(Vector{<:Integer})  # Integer
f(Vector)  # true
f(Tuple{<:Number, <:AbstractString})  # "hi"
1 Like