# Strange behavior of arrays of UnionAll type

**URL:** <https://discourse.julialang.org/t/strange-behavior-of-arrays-of-unionall-type/9440>\
**Category:** General Usage\
**Created:** [March 2, 2018, 7:15am UTC](https://discourse.julialang.org/t/strange-behavior-of-arrays-of-unionall-type/9440 "2018-03-02T07:15:37Z")\
**Posts on this page:** 4\
**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:** [March 2, 2018, 7:15am UTC](https://discourse.julialang.org/t/strange-behavior-of-arrays-of-unionall-type/9440/1 "2018-03-02T07:15:37Z")

</div>

Though I thought I understood UnionAll types pretty well by now, some behavior of them are still hard to understand.

Consider the following example:

```julia
julia> struct MyType{N,S<:NTuple{N}}
           t::S
       end

```

`MyType` has two type parameters `N` and `S`, where the latter depends on the former. I create instances of two different `MyType` types—one with an `Int64` tuple and another with a `Float64` tuple—and store them in a vector:

```julia
julia> m1 = MyType{3,NTuple{3,Int64}}((1,2,3))
MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))

julia> m2 = MyType{3,NTuple{3,Float64}}((1.0,2.0,3.0))
MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))

julia> v = [m1,m2]
2-element Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}:
 MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
 MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))

```

And here goes some behavior that I don’t understand: why does the following generate an error:

```julia
julia> v::Vector{<:MyType{3}}
ERROR: TypeError: typeassert: expected Array{#s1,1} where #s1<:(MyType{3,S} where S<:(Tuple{T,T,T} where T)), got Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}

```

even though the following does not?

```julia
julia> v::Vector{<:(MyType{3,S} where {S})}
2-element Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}:
 MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
 MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))

```

I find this strange because `MyType{3}` in the failing example is also a UnionAll type that is not much different from `MyType{3,S} where {S}` in the succeeding example:

```julia
julia> MyType{3}
MyType{3,S} where S<:(Tuple{T,T,T} where T)

```

Another strange behavior. `v` is typed as

```julia
julia> typeof(v)
Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}

```

where the type parameter `N` is not specified. However, because both entries of `v` are `MyType` with length-3 tuples, I thought we should be able to fix `N` to 3 in the above type, but that was not the case:

```julia
julia> v::Array{MyType{3,S} where S<:(Tuple{Vararg{T,3}} where T),1}
ERROR: TypeError: typeassert: expected Array{MyType{3,S} where S<:(Tuple{Vararg{T,3}} where T),1}, got Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}

```

I wonder if somebody could explain these behaviors.

The main reason for asking this question: I had a custom type similar to `MyType`, and wanted to create a function taking a vector similar to the above `v`, but specifying the type of the function’s argument as `::AbstractVector{<:MyType{3}}` did not work because of the phenomenon described above.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [March 3, 2018, 3:38am UTC](https://discourse.julialang.org/t/strange-behavior-of-arrays-of-unionall-type/9440/2 "2018-03-03T03:38:15Z")

</div>

After a couple of rounds of experimenting, I think I can raise one more question and then answer the questions above.

```julia
julia> typeof([m1,m2])
Array{MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N,1}

julia> Vector{<:MyType{3}}
Array{#s5,1} where #s5<:(MyType{3,S} where S<:(Tuple{T,T,T} where T))

julia> Vector{<:(MyType{3,S} where {S})}
Array{#s6,1} where #s6<:(MyType{3,S} where S)

```

The first surprising bit here is that when packaging `m1` and `m2` together in a vector, the information about the tuple size `N` is lost in the triangular type parameters but not in the top level parameters. So my question is, why is this happening?

Now given this unfortunate event, let’s try and hack things around. If `v` is defined as:

```julia
v = (MyType{3,S} where {T, S<:NTuple{3,T}})[m1,m2]

```

thus forcefully preserving the inner tuple size parameter, things work out as expected.

```julia
julia> v = (MyType{3,S} where {T, S<:NTuple{3,T}})[m1,m2]
2-element Array{MyType{3,S} where S<:(Tuple{T,T,T} where T),1}:
 MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
 MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))

julia> v::Vector{<:MyType{3}}
2-element Array{MyType{3,S} where S<:(Tuple{T,T,T} where T),1}:
 MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
 MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))

julia> v::Vector{<:(MyType{3,S} where {S})}
2-element Array{MyType{3,S} where S<:(Tuple{T,T,T} where T),1}:
 MyType{3,Tuple{Int64,Int64,Int64}}((1, 2, 3))
 MyType{3,Tuple{Float64,Float64,Float64}}((1.0, 2.0, 3.0))

```

Notice that `Vector{<:MyType{3}}` is short for `Array{#s5,1} where #s5<:(MyType{3,S} where S<:(Tuple{T,T,T} where T))`, that is you are only allowed to choose `#s5` from the subtypes of `(MyType{3,S} where S<:(Tuple{T,T,T} where T))` where the tuple size is properly inferred. However, `Vector{<:(MyType{3,S} where {S})}` is short for `Array{#s6,1} where #s6<:(MyType{3,S} where S) `, so `#s6` is now free to be any subtype of `(MyType{3,S} where S) `. In other words, because `[m1,m2]` has a less specialized element type than the assertion type, it is not passing the assertion test. This is just a more complicated example of:

```julia
julia> Real[1,2]::Vector{<:Integer}
ERROR: TypeError: typeassert: expected Array{#s1,1} where #s1<:Integer, got Array{Real,1}

julia> Integer[1,2]::Vector{<:Real}
2-element Array{Integer,1}:
 1
 2

```

So it seems the take home lesson (or bug) here is that `typejoin`ing doesn’t work as expected for parametric types when constructing arrays of custom types.

```julia
julia> typeof(m1)
MyType{3,Tuple{Int64,Int64,Int64}}

julia> typeof(m2)
MyType{3,Tuple{Float64,Float64,Float64}}

julia> typejoin(typeof(m1), typeof(m2))
MyType{3,S} where S<:(Tuple{Vararg{T,N}} where T) where N

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [March 3, 2018, 7:26am UTC](https://discourse.julialang.org/t/strange-behavior-of-arrays-of-unionall-type/9440/3 "2018-03-03T07:26:39Z")

</div>

> [@mohamed82008](#):
>
> the take home lesson (or bug)

I don’t know if this is a bug, but it should warrant further discussion in an issue if one does not exist already.

---

<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:** [March 5, 2018, 3:04am UTC](https://discourse.julialang.org/t/strange-behavior-of-arrays-of-unionall-type/9440/4 "2018-03-05T03:04:11Z")

</div>

Thanks for the inputs! An issue about this problem is created [here](https://github.com/JuliaLang/julia/issues/26321).
