# How to passing vargs... to a function without allocation?

**URL:** https://discourse.julialang.org/t/how-to-passing-vargs-to-a-function-without-allocation/86824
**Category:** Performance
**Created:** [September 5, 2022, 10:25pm UTC](https://discourse.julialang.org/t/how-to-passing-vargs-to-a-function-without-allocation/86824 "2022-09-05T22:25:26Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![MrBug](https://avatars.discourse-cdn.com/v4/letter/m/bbe5ce/32.png) [@MrBug](https://discourse.julialang.org/u/MrBug)
#### Post date: [September 5, 2022, 10:25pm UTC](https://discourse.julialang.org/t/how-to-passing-vargs-to-a-function-without-allocation/86824/1 "2022-09-05T22:25:26Z")

</div>

I would like to unpack a tuple parameter of a function, then pass it to another function. The naive implementation in the following causes allocations which becomes a bottleneck for my application.  
Is there any way to remove such allocations?

```julia
julia> t=(1.0, 2.0)
(1.0, 2.0)

julia> function f(x, y)
           return x+y
       end
f (generic function with 1 method)

julia> function g(t)
           return f(t...)
       end
g (generic function with 1 method)

julia> g(t)
3.0

julia> @time g(t)
  0.000003 seconds (1 allocation: 16 bytes)
3.0

```

I am thinking about a macro. But I don’t know how to handle a user input tuple of different datatype and length.  
Thank you for your help!

---

<div class="post-metadata">

### Author: ![jmair](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jmair/32/35117_2.png) [@jmair](https://discourse.julialang.org/u/jmair)
#### Post date: [September 5, 2022, 10:56pm UTC](https://discourse.julialang.org/t/how-to-passing-vargs-to-a-function-without-allocation/86824/2 "2022-09-05T22:56:23Z")

</div>

I know this is not as elegant, but what happens with:

```julia
g(t) = f(t[1], t[2])

```

If you actually have a variable number of elements you can try and use an `NTuple` and dispatch on the number of elements (I think).

You can experiment with `@inbounds` and `@inline` to see if that makes any performance difference.

---

<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: [September 5, 2022, 11:03pm UTC](https://discourse.julialang.org/t/how-to-passing-vargs-to-a-function-without-allocation/86824/3 "2022-09-05T23:03:19Z")

</div>

What you are doing already is perfectly fine, and should not allocate. It is probably an artefact of benchmarking, since `t` is a non-`const` global.

BenchmarkTools.jl should give more reliable results.

But, as I said, your code is otherwise already how it should be. If you are seeing a bottleneck outside of the benchmarking itself, I suspect it is related to some part of the code you haven’t shared.

---

<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: [September 5, 2022, 11:12pm UTC](https://discourse.julialang.org/t/how-to-passing-vargs-to-a-function-without-allocation/86824/4 "2022-09-05T23:12:41Z")

</div>

^exactly that. This is what happens when `t` is a local variable:

```julia
julia> let
         t = (1.0, 2.0)
         @time g(t)
       end
  0.000000 seconds
3.0

```

To be clear, the function `g` is still global but it is also implicitly `const`, which the compiler can also optimize. It’s non-`const` globals that require a bit of overhead (16 byte allocation is a good tell).

---

<div class="post-metadata">

### Author: ![Vincent\_Picaud](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vincent_picaud/32/3108_2.png) [@Vincent\_Picaud](https://discourse.julialang.org/u/Vincent_Picaud)
#### Post date: [September 6, 2022, 9:54am UTC](https://discourse.julialang.org/t/how-to-passing-vargs-to-a-function-without-allocation/86824/5 "2022-09-06T09:54:05Z")

</div>

I think this is mainly a benchmark artefact. It is safer to use [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl).

The right syntax to perform the benchmark is:

```julia
julia> using BenchmarkTools

julia> @benchmark g($t)
BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max): 3.177 ns … 212.467 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 3.195 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 3.221 ns ± 2.131 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

     █ ▁▁                                   
  ▄▄▃█▁▁▄▄▂▄▁▁▂▂▁▂▁▁▂▁▂▁█▁██▁▂▆▁▄▄▁▁▃▂▂▁▂▁▂▁▁▂▁▁▂▁▁▁▁▁▂▁▁▂▂▁▂ ▃
  3.18 ns Histogram: frequency by time 3.22 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

→ you can check that there is no allocation.

It is important to notice the ‘$’ in ‘@benchmark g($t)’. As BenchmarkTool.jl doc says:

> If the expression you want to benchmark depends on external variables, you should use [`$` to “interpolate”](https://juliaci.github.io/BenchmarkTools.jl/stable/manual/#Interpolating-values-into-benchmark-expressions) them into the benchmark expression to [avoid the problems of benchmarking with globals](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-global-variables). Essentially, any interpolated variable `$x` or expression `$(...)` is “pre-computed” before benchmarking begins:
> 
> ```julia
> julia> A = rand(3,3); 
> julia> @btime inv($A); # we interpolate the global variable A with $A 1.191 μs (10 allocations: 2.31 KiB) julia> @btime inv($(rand(3,3))); # interpolation: the rand(3,3) call occurs before benchmarking 1.192 μs (10 allocations: 2.31 KiB) 
> julia> @btime inv(rand(3,3)); # the rand(3,3) call is included in the benchmark time 1.295 μs (11 allocations: 2.47 KiB)
> 
> ```
