# Union type confusion

**URL:** <https://discourse.julialang.org/t/union-type-confusion/114366>\
**Category:** General Usage\
**Created:** [May 16, 2024, 4:03pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366 "2024-05-16T16:03:54Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [May 16, 2024, 4:03pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366/1 "2024-05-16T16:03:54Z")

</div>

Consider an abstract type with a parameter `T` and its two concrete types:

```julia
abstract type AbstractMyType{T} end
struct MyType1{T} <: AbstractMyType{T} end
struct MyType2{T} <: AbstractMyType{T} end

```

Construct a vector of instances of the two concrete types with the same parameter `T = Int`:

```julia
julia> v = [MyType1{Int}(), MyType2{Int}()]
2-element Vector{AbstractMyType{Int64}}:
 MyType1{Int64}()
 MyType2{Int64}()

```

The result is a vector of the abstract type.

Now, here is a thing that I don’t understand:

```julia-repl
julia> v isa AbstractVector{AbstractMyType{T}} where {T<:Number}
true

julia> v isa AbstractVector{AbstractMyType{<:Number}}
false

```

I thought `AbstractMyType{<:Number}` was a shorthand of `AbstractMyType{T} where {T<:Number}`. Why do they produce the different results?

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [May 16, 2024, 4:14pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366/2 "2024-05-16T16:14:04Z")

</div>

> [@wsshin](#):
>
> I thought `AbstractMyType{<:Number}` was a shorthand of `AbstractMyType{T} where {T<:Number}`.

It is:

```julia
julia> v isa AbstractVector{AbstractMyType{T} where T <: Number}
false

```

The point is that

```julia
AbstractVector{AbstractMyType{T} where T <: Number}

```

is not the same as

```julia
AbstractVector{AbstractMyType{T}} where T <: Number

```

The second one subsumes all `AbstractVector`s whose element type is some type of the form `AbstractMyType{T}` where `T` is a subtype of `Number`. The first one applies only to `AbstractVector`s whose element type is exactly `AbstractMyType{<:Number}`.

---

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [May 16, 2024, 4:29pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366/3 "2024-05-16T16:29:27Z")

</div>

> [@matthias314](#):
>
> `AbstractVector{AbstractMyType{T} where T <: Number}`

Could you give an example vector of this type? Not sure how to construct a vector whose element type is exactly `AbstractMyType{<:Number}`.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [May 16, 2024, 4:38pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366/4 "2024-05-16T16:38:22Z")

</div>

```julia
julia> v = AbstractMyType{<:Number}[MyType1{Int}(), MyType2{Number}(), MyType2{Real}()]
3-element Vector{AbstractMyType{<:Number}}:
 MyType1{Int64}()
 MyType2{Number}()
 MyType2{Real}()

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [May 16, 2024, 4:40pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366/5 "2024-05-16T16:40:47Z")

</div>

I don’t think Julia’s array literals will divine out such an eltype, but you can explicitly request it:

```julia
julia> AbstractMyType{<:Number}[MyType2{Int}(), MyType1{Float64}()]
2-element Vector{AbstractMyType{<:Number}}:
 MyType2{Int64}()
 MyType1{Float64}()

```

But more to your original point, you can add _another_ where clause to say that it can match _any_ subtype of `AbstractMyType` as long as its parameter is `<: Number`.

```julia
julia> v = [MyType1{Int}(), MyType2{Int}()];

julia> v isa AbstractVector{<:AbstractMyType{<:Number}}
true

```

---

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [May 16, 2024, 6:53pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366/6 "2024-05-16T18:53:49Z")

</div>

> [@mbauman](#):
>
> ```julia
> julia> v = [MyType1{Int}(), MyType2{Int}()];
> 
> julia> v isa AbstractVector{<:AbstractMyType{<:Number}}
> true
> 
> ```

A good point, but I would like to note that this also includes types like `Vector{MyType{Int}}` whose eltype is the concrete `MyType{Int}`, whereas `AbstractVector{AbstractMyType{T}} where {T<:Number}` excludes such types. Therefore, the two type specifications are different.

There are cases where this difference matters. For example, I am actually trying to specify the type of `v` in a function signature as

```julia
function myfun(v::AbstractVector{AbstractMyType{T}}) where {T<:Number}

```

in order to make sure that the `eltype` of `v` is always the abstract `AbstractMyType`, , because `myfun` is expected to take aways a vector of abstract-type elements.

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [May 16, 2024, 7:11pm UTC](https://discourse.julialang.org/t/union-type-confusion/114366/7 "2024-05-16T19:11:22Z")

</div>

> [@wsshin](#):
>
> There are cases where this difference matters. For example, I am actually trying to specify the type of `v` in a function signature as
> 
> ```julia
> function myfun(v::AbstractVector{AbstractMyType{T}}) where {T<:Number}
> 
> ```
> 
> in order to make sure that the `eltype` of `v` is always the abstract `AbstractMyType`, , because `myfun` is expected to take aways a vector of abstract-type elements.

Why would you want to do that? Coming from generic programming a function taking a vector of `AbstractMyType`s could only do some reasonable things with its inputs, such as iterating over the vector and calling some methods on some elements – which would need to work for `AbstractMyType`s. In any case, the function should probably also work with vectors holding some concrete subtype such as `MyType1`.  
In OOP this idea is known as the [Liskov substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) and the related quote by Jon Postel:

> be conservative in what you do, be liberal in what you accept from others
