# Declaring types: Vector{Union{Int64, Matrix{Int64}}} is much slower than Vector{Any}, why is that?

**URL:** <https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480>\
**Category:** Performance\
**Tags:** question\
**Created:** [July 1, 2024, 3:20pm UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480 "2024-07-01T15:20:43Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![13299118606](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/13299118606/32/49095_2.png) [@13299118606](https://discourse.julialang.org/u/13299118606)\
**Post date:** [July 1, 2024, 3:20pm UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/1 "2024-07-01T15:20:43Z")

</div>

Declaring types: Vector{Union{Int64, Matrix{Int64}}} is much slower than Vector{Any}, why is that?

The following code is different from my declarations. f0 is not declared, f1 is declared ::Vector{Any}, and f2 is declared ::Vector{Union{Int64, Matrix{Int64}}}

```julia
function f0(path_info)
trace_iteration = []
  count=0
  for k in 1:length(path_info)
    p_path=path_info[k]
    t1::Int64 = p_path[1]
    t2::Int64 = p_path[2]
    if t1 < 5 && t2 <5
    count += 1
    end
  end
  push!(trace_iteration, count)
  return trace_iteration
end

function f1(path_info)
  trace_iteration = []
  count=0
  for k in 1:length(path_info)
    p_path::Vector{Any}=path_info[k]
    t1::Int64 = p_path[1]
    t2::Int64 = p_path[2]
    if t1 < 5 && t2 <5
    count += 1
    end
  end
  push!(trace_iteration, count)
  return trace_iteration
end

function f2(path_info)
  trace_iteration = []
  count=0
  for k in 1:length(path_info)
    p_path::Vector{Union{Int64, Matrix{Int64}}}=path_info[k]
    t1::Int64 = p_path[1]
    t2::Int64 = p_path[2]
    if t1 < 5 && t2 <5
         count += 1
    end
  end
  push!(trace_iteration, count)
  return trace_iteration
end

path_info0=[[rand(1:10),rand(1:10),rand(1:10),rand(1:10),rand(Int,2,2)] for i in 1:1000000]

@btime f0(path_info0) #16ms
@btime f1(path_info0) #15.6ms
@btime f2(path_info0) # 243ms

```

It can be seen that declaring a union type will be 10 times slower. Is there any way to declare the variable to speed up the function?

```julia
versioninfo()
Julia Version 1.10.0
Commit 3120989f39 (2023-12-25 18:01 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 20 × 12th Gen Intel(R) Core(TM) i7-12700
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, alderlake)
  Threads: 1 on 20 virtual cores
Environment:
  JULIA_NUM_THREADS1 = 1
  JULIA_PKG_SERVER = https://mirrors.bfsu.edu.cn/julia
  JULIA_PYTHONCALL_EXE = @PyCall
  JULIA_EDITOR = code
  JULIA_NUM_THREADS =

```

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [July 1, 2024, 3:22pm UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/2 "2024-07-01T15:22:36Z")

</div>

you likely want `Vector{<:Union{Int64, Matrix{Int64}}}`. Your current code is making a copy of the Vector since `Vector{Int}` is not a subtype of `Vector{Union{Int64, Matrix{Int64}}}`

---

<div class="post-metadata">

**Author:** ![13299118606](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/13299118606/32/49095_2.png) [@13299118606](https://discourse.julialang.org/u/13299118606)\
**Post date:** [July 1, 2024, 3:33pm UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/3 "2024-07-01T15:33:07Z")

</div>

An error will occur after modification

```julia
 f(path_info0)

ERROR: MethodError: no method matching (Vector{<:Union{Int64, Matrix{Int64}}})(::Vector{Any})
Stacktrace:
[1] convert(::Type{Vector{<:Union{Int64, Matrix{Int64}}}}, a::Vector{Any})
@ Base .\array.jl:665

```

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [July 1, 2024, 4:22pm UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/4 "2024-07-01T16:22:16Z")

</div>

I’ll recommend you move your type assertions to the right side like

```julia
p_path = path_info[k]::Vector{Union{Int64, Matrix{Int64}}}
t1 = p_path[1]::Int64
t2 = p_path[2]::Int64

```

As a previous poster suggested, part of your issue might be unintended conversions. When annotated on the right side, no attempt at conversion is made. Instead, an error will be thrown immediately if the annotation does not match the data (as suggested, you might need to add a `<:` or reconsider your data structure). This will prevent such accidents.

If your data actually looks like this (with each index always having the same type - e.g., 4 `Int64` and then a `Matrix{Int64}`), you might consider using a `Tuple` or custom `struct` instead of `Vector{Union{Int64, Matrix{Int64}}}`. For example,

```julia-repl
julia> path_info0=[(rand(1:10),rand(1:10),rand(1:10),rand(1:10),rand(Int,2,2)) for i in 1:1000000]
1000000-element Vector{Tuple{Int64, Int64, Int64, Int64, Matrix{Int64}}}
...

```

has no type uncertainty in the first place.

---

<div class="post-metadata">

**Author:** ![13299118606](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/13299118606/32/49095_2.png) [@13299118606](https://discourse.julialang.org/u/13299118606)\
**Post date:** [July 2, 2024, 2:10am UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/5 "2024-07-02T02:10:28Z")

</div>

Thank you very much, tuples are indeed much faster, but if it is a vector, setting the type on the right side will still cause an error:

```julia
function f(path_info)
trace_iteration = []

count=0
for k in 1:length(path_info)
p_path=path_info[k]::Vector{Union{Int64, Matrix{Int64}}}
t1 = p_path[1]::Int64
t2 = p_path[2]::Int64
if t1 < 5 && t2 <5
count += 1
end
end
push!(trace_iteration, count)

return trace_iteration
end

```

error:

```julia
 p_path=path_info[k]::Vector{Union{Int64, Matrix{Int64}}} 

f(path_info0)
ERROR: TypeError: in typeassert, expected Vector{Union{Int64, Matrix{Int64}}}, got a value of type Vector{Any}
Stacktrace:
[1] f(path_info::Vector{Vector{Any}})

```

error2:

```julia
 p_path=path_info[k]::Vector{<:Union{Int64, Matrix{Int64}}}

f(path_info0)
ERROR: TypeError: in typeassert, expected Vector{<:Union{Int64, Matrix{Int64}}}, got a value of type Vector{Any}
Stacktrace:
 [1] f(path_info::Vector{Vector{Any}})

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 2, 2024, 3:47am UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/6 "2024-07-02T03:47:40Z")

</div>

Your problems start before your before your function. The argument you are passing in is a `Vector{Vector{Any}}`.

Continuing to use `Vector{Any}` within your function is faster because it does not require conversion and allocation of a new array.

The errors are occurring because you are using assertions on the right hand side, but the variables you are asserting to be of type `Vector{<:Union{Int64, Matrix{Int64}}}` are not of that type.

To start fixing this properly we need to change the type of your input argument `path_info`. Could you show us how you construct this?

Also looking at what I can see within your function, this is not good:

> [@13299118606](#):
>
> ```julia
> trace_iteration = []
> 
> ```

That starts `trace_iteration` as a `Vector{Any}`. From what I can tell you probably want

```julia
trace_iteration = Int[]

```

The types of the two declarations are illustrated here:

```julia
julia> typeof([])
Vector{Any} (alias for Array{Any, 1})

julia> typeof(Int[])
Vector{Int64} (alias for Array{Int64, 1})

julia> push!([], 3.0)
1-element Vector{Any}:
 3.0

julia> push!(Int[], 3.0)
1-element Vector{Int64}:
 3

```

From what what I can tell your `path_info` should probably be `Vector{Vector{Int}}` not a `Vector{Vector{Any}}`.

To convert your `path_info` from `Vector{Vector{Any}}` to `Vector{Vector{Int}}` do the following.

```julia
julia> path_info = [Any[1, 2, 3], Any[4, 5, 6]]
2-element Vector{Vector{Any}}:
 [1, 2, 3]
 [4, 5, 6]

julia> path_info = map(path_info) do p_path
           Int.(p_path)
       end
2-element Vector{Vector{Int64}}:
 [1, 2, 3]
 [4, 5, 6]

```

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [July 2, 2024, 5:47am UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/7 "2024-07-02T05:47:33Z")

</div>

> [@13299118606](#):
>
> It can be seen that declaring a union type will be 10 times slower. Is there any way to declare the variable to speed up the function?

Normally, there is never any speed gain in declaring the types of variables. The exception is if you have type instability in your program, as you have. I.e. you have a variable `path_info` of type `Vector{Vector{Any}}`, so that the compiler can’t know the type of `t1` and `t2`. The priority for performant programs is to get rid of type instabilities in critical loops.

If you for some reason can’t get rid of the type instability, but you anyway know the type of the vector elements, the simplest is to assert the type like `t1 = p_path[1]::Int`. This will throw an error if it’s not an `Int`.

Depending on your actual data and computations, there may be other options. E.g. a function barrier which will incur a single dynamic dispatch, but otherwise will be type stable.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [July 2, 2024, 7:12am UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/8 "2024-07-02T07:12:19Z")

</div>

> [@mikmoore](#):
>
> I’ll recommend you move your type assertions to the right side like

I would recommend removing the assertions _entirely_, just leave this to the compiler.

And _definitely_, as @mkitti says, fix this part:

> [@13299118606](#):
>
> `trace_iteration = []`

If your code ever has `[]`, it’s a red a flag for performance.

---

<div class="post-metadata">

**Author:** ![13299118606](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/13299118606/32/49095_2.png) [@13299118606](https://discourse.julialang.org/u/13299118606)\
**Post date:** [July 2, 2024, 7:22am UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/9 "2024-07-02T07:22:53Z")

</div>

Thank you very much. It is indeed necessary to stabilize the variable type at the beginning. If it is a mixed-type vector, tuples need to be used to solve the mixed-type problem. I have solved the corresponding performance problem.

---

<div class="post-metadata">

**Author:** ![13299118606](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/13299118606/32/49095_2.png) [@13299118606](https://discourse.julialang.org/u/13299118606)\
**Post date:** [July 2, 2024, 7:24am UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/10 "2024-07-02T07:24:22Z")

</div>

> [@mkitti](#):
>
> `trace_iteration = Int[]`

Thank you very much. It is indeed necessary to stabilize the variable type at the beginning. If it is a mixed-type vector, tuples need to be used to solve the mixed-type problem. I have solved the corresponding performance problem.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 2, 2024, 7:48am UTC](https://discourse.julialang.org/t/declaring-types-vector-union-int64-matrix-int64-is-much-slower-than-vector-any-why-is-that/116480/11 "2024-07-02T07:48:48Z")

</div>

As others have said, the difference is probably the copying from the conversions every time you assign to an annotated variable. `convert` doesn’t always make a copy, it depends on the implementation. `convert(Any, x)` just returns the same instance, and generally `convert(T, x::T)` will too.

Here’s a simple way to check, how do the timings change when you change

```julia
path_info0=Vector{Union{Int64, Matrix{Int64}}}[[rand(1:10),rand(1:10),rand(1:10),rand(1:10),rand(Int,2,2)] for i in 1:1000000]

```

so `convert` won’t need to do anything in `f2`?

> [@Oscar\_Smith](#):
>
> you likely want `Vector{<:Union{Int64, Matrix{Int64}}}`

> [@13299118606](#):
>
> `ERROR: MethodError: no method matching (Vector{<:Union{Int64, Matrix{Int64}}})(::Vector{Any})`

I don’t think abstract types are generally implemented for `convert` unless the instance is already of the type because the choice of the concrete type would be ambiguous and arbitrary otherwise.
