# Tuple vs Union as struct parameter

**URL:** <https://discourse.julialang.org/t/tuple-vs-union-as-struct-parameter/29820>\
**Category:** General Usage\
**Created:** [October 12, 2019, 2:54pm UTC](https://discourse.julialang.org/t/tuple-vs-union-as-struct-parameter/29820 "2019-10-12T14:54:21Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Qiyamah](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/qiyamah/32/2660_2.png) [@Qiyamah](https://discourse.julialang.org/u/Qiyamah)\
**Post date:** [October 12, 2019, 2:54pm UTC](https://discourse.julialang.org/t/tuple-vs-union-as-struct-parameter/29820/1 "2019-10-12T14:54:21Z")

</div>

This seems OK.

```nohighlight
julia> struct TupleTest{T<:Tuple}
       end
julia> TupleTest{Tuple{Int,Float64}}
TupleTest{Tuple{Int64,Float64}}

```

However this is not:

```julia
julia> struct UnionTest{U<:Union}
       end
julia> UnionTest{Union{Int,Float64}}
ERROR: TypeError: in UnionTest, in U, expected U<:Union, got Type{Union{Float64, Int64}}
Stacktrace:
 [1] top-level scope at REPL[5]:1

```

why is that?

Basically my question boils down to:

```julia
julia> Union{Int,Float64} <: Union
false

julia> Tuple{Int,Float64} <: Tuple
true

```

why?

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [October 12, 2019, 5:36pm UTC](https://discourse.julialang.org/t/tuple-vs-union-as-struct-parameter/29820/2 "2019-10-12T17:36:21Z")

</div>

I don’t fully understand the rules here, but

```julia
julia> Union{Int,Float64} <: Union{Any}
true

```

It looks as if the comparison used `promote` on each union and then applies the `<:` comparison. For example:

```julia
julia> Union{Int,Float64} <: Union{UInt8,Real}
true
julia> Union{Int,Float64} <: Union{UInt8,Float32}
false

```

I don’t see this in the offical docs though.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [October 12, 2019, 9:05pm UTC](https://discourse.julialang.org/t/tuple-vs-union-as-struct-parameter/29820/3 "2019-10-12T21:05:08Z")

</div>

Both `Tuple` and `Union` are special in Julia and can’t just be thought of as regular parametric types. The weirdness of `Tuple` is described quite well [here](https://docs.julialang.org/en/v1/manual/types/#Tuple-Types-1), but the section for `Union` types could probably be improved.

The first thing to note about `Union` is that there can never be an instance of an object that has a union type as its type. Instances must always have a concrete type, unions just represent a set of types that an object could be, and can also allow the compiler to optimize small unions, for example. As such it simply isn’t possible to dispatch just based on whether something is a union type, since the actual object passed to the function will always have a concrete type, and the function being dispatched on doesn’t know whether your code is type stable or not.

As such, what you are trying to do doesn’t make much sense, since `Union` is not an abstract type, that `Union{Int,Float64}` is a subtype of, but instead, `Union{Int,Float64}` is only a subtype of types, that both `Int` and `Float64` are a subtype of, so e.g. `Union{Int,Float64} <: Real == true`. If you want to check, whether a type (not an object) is a union type, you could to this with `Union{Int,Float64} isa Union`, for example, since `Union` is not the supertype of union types, but union types are actually instances of type `Union`.

@hendri54 Union types actually don’t rely on `promote` at all, but instead, when checking whether they are a subtype of something, it is checked, whether every member of the union is a subtype, so it’s easiest to just think of union types as set unions, and `<:` as checking whether the argument on the left is a subset of the one on the right. Also note that `Union{Any}` is just equivalent to `Any` and `Union{UInt8,Real}` is equivalent to `Real`, since `UInt8` is just a subtype of `Real`. Order also doesn’t matter for union types.

I hope this hasn’t been too confusing, and it cleared at least some things up. Anybody feel free to correct me, if I glossed over some things.

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [October 13, 2019, 12:34pm UTC](https://discourse.julialang.org/t/tuple-vs-union-as-struct-parameter/29820/4 "2019-10-13T12:34:39Z")

</div>

Very helpful - thank you.

So, if I understand correctly, `<:` asks: “is any member of the `Union` on the left guaranteed to be a subtype of any member of the union on the right?” If so, return `true`; otherwise `false`.

That makes sense.
