Deuxis
Deuxis

Reputation: 239

Julia: Match any type belonging to a Union

I have a Union{Type1, Type2, Type3}, which matches all values whose type is one of those types. But how do I match the types themselves?

MyU = Union{Float64, Int, Array}
a::MyU = 3.5 # works
a = 5 # works
a = [1, 2, 3] # works
# but of course
a = Float64 # nope
a = Int # nope
a = Array # nope

With normal types this is usually achieved via Type{MyType}, whose only value is MyType. But Type{MyU} matches only MyU, and not the types it contains. How do I match those?

I can of course just use DataType, but this has two issues:

  1. It matches any type, not only those I want.
  2. It doesn't match UnionAll types, like Array.

My current workaround is Union{DataType,UnionAll}, but it's an ugly hack that is additionally bound to crash and burn if I include another Union or some other non-concrete type into MyU.

My other solution is to make a second, parallel Union like so:

MyU = Union{Float64, Int, Array}
MyUT = Union{Type{Float64}, Type{Int}, Type{Array}}

It does work and is more strict, but it's also ugly and introduces large possibility of human error with manually keeping those in sync.

Upvotes: 4

Views: 686

Answers (1)

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69939

You could consider something like this to avoid macros (which can be tricky):

gettypes(u::Union) = [u.a; gettypes(u.b)]
gettypes(u) = [u]
typewrap(u) = Union{[Type{v} for v in gettypes(u)]...}

and then:

julia> MyU = Union{Float64, Int, Array}
Union{Float64, Int64, Array}

julia> MyUT = typewrap(MyU)
Union{Type{Array}, Type{Float64}, Type{Int64}}

EDIT

As an additional note, you can define gettypes as one liner like this:

gettypes(u) = u isa Union ? [u.a; gettypes(u.b)] : [u]

EDIT 2

Or yet simpler without an intermediate array:

typewrap(u) = u isa Union ? Union{Type{u.a}, typewrap(u.b)} : Type{u}

Upvotes: 4

Related Questions