# Vararg vs Tuple{Vararg} performance

**URL:** <https://discourse.julialang.org/t/vararg-vs-tuple-vararg-performance/35670>\
**Category:** Performance\
**Created:** [March 6, 2020, 11:13pm UTC](https://discourse.julialang.org/t/vararg-vs-tuple-vararg-performance/35670 "2020-03-06T23:13:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![SnoopyDoowop](https://avatars.discourse-cdn.com/v4/letter/s/5fc32e/32.png) [@SnoopyDoowop](https://discourse.julialang.org/u/SnoopyDoowop)\
**Post date:** [March 6, 2020, 11:13pm UTC](https://discourse.julialang.org/t/vararg-vs-tuple-vararg-performance/35670/1 "2020-03-06T23:13:53Z")

</div>

Hello!

While trying out some things in the julia REPL to see how a[i…] = x is transformed into setindex!(a, x, i…). I came across multiple questions :

I am wondering why the prototype of setindex! is `setindex!(A::AbstractArray,X::Any,inds::Vargarg{Any})`  
and not `setindex!(A::AbstractArray,X::Any,inds:Tuple{Vararg{Any})`

I thought it was for performance reasons but when i tried to replicate the behavior and benchmark it with BenchmarkTools.jl, the results were not exactly what i expected.

If I declare those two lambda functions:

```julia
f = (a, b::Vararg) -> b

```

```julia
g = (a, b::Tuple{Vararg}) -> b

```

And benchmark (with 100 000 samples) `f(1, 2)` and `g(1, (2,))` then effectively `f` is a little faster than `g`by approx 0.5 nano-seconds in median time.

BUT if i re-run this benchmark with` f(1, 2, 3)` and `g(1, (2, 3))` then `f` is terribly slower that `g`. Where `g` takes **15 ns** in median time, `f` takes **171 ns**??

1: First question: is this performance gap normal ? Is the first proto for setindex! preferred over the second because setindex! is practically never called with multiple indices?

Moreover, It seems like there isn’t a way to define easily a Tuple{Vararg} and extract its content via the argument destructuring syntax.

I can do

```julia
f = (a, b) -> b

```

and

```julia
f = (a, b...) -> b

```

and

```julia
g = (a, (b,)) -> b

```

but not

```julia
g = (a, (b...,)) -> b

```

2: Am I missing something syntactically speaking ?

Anyway, sorry for the long post… here is my versioninfo() in case. Thanks! 🙂

julia\> versioninfo()  
Julia Version 1.3.1  
Commit 2d5741174c (2019-12-30 21:36 UTC)  
Platform Info:  
OS: Linux (x86\_64-pc-linux-gnu)  
CPU: Intel(R) Core™ i7-8750H CPU @ 2.20GHz  
WORD\_SIZE: 64  
LIBM: libopenlibm  
LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

---

<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:** [March 6, 2020, 11:37pm UTC](https://discourse.julialang.org/t/vararg-vs-tuple-vararg-performance/35670/2 "2020-03-06T23:37:01Z")

</div>

1. There shouldn’t be a performance difference here at all, splatting reasonably sized Tuples should not add any allocations or runtime operations. The difference to passing Tuples is just that using `Vararg` (or `x...`, equivalently) can be a bit less verbose to write and make for a more consistent API. The difference you are observing is probably due to the way you are benchmarking this. Are you using `@btime` from `BenchmarkTools.jl` and if yes, how are you interpolating the function arguments? 0.5 ns should be about 1 clock cycle, which is probably just due to random noise.
2. `x...` should be equivalent to `x::Vararg`. Allowing to destructurjng Tuples in function arguments as `f(x, (a, b...))` has been proposed before, which would make your fourth example work as well, but for now, this is invalid syntax. `(a, (b...,)) -> b` would be equivalent to `(a, b::Tuple) -> b` anyways. Other than that, I don’t really see anything you are missing.

---

<div class="post-metadata">

**Author:** ![SnoopyDoowop](https://avatars.discourse-cdn.com/v4/letter/s/5fc32e/32.png) [@SnoopyDoowop](https://discourse.julialang.org/u/SnoopyDoowop)\
**Post date:** [March 7, 2020, 12:00am UTC](https://discourse.julialang.org/t/vararg-vs-tuple-vararg-performance/35670/4 "2020-03-07T00:00:06Z")

</div>

1. Here is exactly what I’m doing, no more, no less

```julia
julia> f = (a, b::Vararg) -> b
#3 (generic function with 1 method)

julia> g = (a, b::Tuple{Vararg}) -> b
#5 (generic function with 1 method)

julia> import BenchmarkTools

julia> BenchmarkTools.@benchmark f(1, 2, 3)
BenchmarkTools.Trial: 
  memory estimate: 32 bytes
  allocs estimate: 1
  --------------
  minimum time: 163.693 ns (0.00% GC)
  median time: 188.505 ns (0.00% GC)
  mean time: 192.193 ns (0.28% GC)
  maximum time: 1.375 μs (83.39% GC)
  --------------
  samples: 10000
  evals/sample: 772

julia> BenchmarkTools.@benchmark g(1, (2, 3))
BenchmarkTools.Trial: 
  memory estimate: 32 bytes
  allocs estimate: 1
  --------------
  minimum time: 14.516 ns (0.00% GC)
  median time: 17.107 ns (0.00% GC)
  mean time: 18.977 ns (3.08% GC)
  maximum time: 947.285 ns (97.69% GC)
  --------------
  samples: 10000
  evals/sample: 998

```

Re-runing the two benchmarks multiple times gave the same results.

1. Ok, Thanks! I’m looking forward to this feature being implemented 😃

---

<div class="post-metadata">

**Author:** ![waralex](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waralex/32/13415_2.png) [@waralex](https://discourse.julialang.org/u/waralex)\
**Post date:** [March 7, 2020, 12:23am UTC](https://discourse.julialang.org/t/vararg-vs-tuple-vararg-performance/35670/5 "2020-03-07T00:23:03Z")

</div>

1. The problem is that global variables are not typed, and Julia checks the types of `f` and` g` (and, I suppose, looks for a suitable method) with every call. Compare with it:

```julia
ulia> const f = (a, b::Vararg) -> b
#7 (generic function with 1 method)

julia> const g = (a, b::Tuple{Vararg}) -> b
#9 (generic function with 1 method)
julia> @benchmark f(1,2,3)
BenchmarkTools.Trial:
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 0.036 ns (0.00% GC)
  median time: 0.039 ns (0.00% GC)
  mean time: 0.039 ns (0.00% GC)
  maximum time: 0.075 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1000

julia> @benchmark g(1,(2,3))
BenchmarkTools.Trial:
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 0.037 ns (0.00% GC)
  median time: 0.039 ns (0.00% GC)
  mean time: 0.039 ns (0.00% GC)
  maximum time: 0.090 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1000

```

---

<div class="post-metadata">

**Author:** ![SnoopyDoowop](https://avatars.discourse-cdn.com/v4/letter/s/5fc32e/32.png) [@SnoopyDoowop](https://discourse.julialang.org/u/SnoopyDoowop)\
**Post date:** [March 7, 2020, 12:30am UTC](https://discourse.julialang.org/t/vararg-vs-tuple-vararg-performance/35670/6 "2020-03-07T00:30:09Z")

</div>

Wow! That explains everything! Thanks 😃
