# Work around splatting to avoid unecessary allocations

**URL:** <https://discourse.julialang.org/t/work-around-splatting-to-avoid-unecessary-allocations/19708>\
**Category:** Performance\
**Created:** [January 16, 2019, 3:59pm UTC](https://discourse.julialang.org/t/work-around-splatting-to-avoid-unecessary-allocations/19708 "2019-01-16T15:59:48Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![konkam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/konkam/32/6598_2.png) [@konkam](https://discourse.julialang.org/u/konkam)\
**Post date:** [January 16, 2019, 3:59pm UTC](https://discourse.julialang.org/t/work-around-splatting-to-avoid-unecessary-allocations/19708/1 "2019-01-16T15:59:48Z")

</div>

Hello everyone,

I am trying to call Base.Iterators.product on a number of arguments which is not fixed in advance, i.e. to call the following function on integer vectors of arbitrary length.

```julia
function indices_below(Λ_max::Union{AbstractArray{U, 1}, Tuple}) where U <: Integer
    return Base.Iterators.product((0:Λi_max for Λi_max in Λ_max)...)
end

```

This function does the job, but it performs some allocations:

```julia
using BenchmarkTools
@btime indices_below($(5,4,6))
  403.880 ns (9 allocations: 480 bytes)
Base.Iterators.ProductIterator{Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}}}((0:5, 0:4, 0:6))

```

However, calling Base.Iterators.product directly on the desired UnitRanges produces no allocation:

```julia

@btime Base.Iterators.product(0:5, 0:4, 0:6)
  1.888 ns (0 allocations: 0 bytes)
Base.Iterators.ProductIterator{Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}}}((0:5, 0:4, 0:6))

```

Do you have any suggestion on how to improve the performance of this function ?

Many thanks

---

<div class="post-metadata">

**Author:** ![tkluck](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkluck/32/15769_2.png) [@tkluck](https://discourse.julialang.org/u/tkluck)\
**Post date:** [January 16, 2019, 4:24pm UTC](https://discourse.julialang.org/t/work-around-splatting-to-avoid-unecessary-allocations/19708/2 "2019-01-16T16:24:21Z")

</div>

`map` seems to work:

```julia
julia> f(x...) = Base.Iterators.product(map(N -> 0:N, x)...)
f (generic function with 1 method)
julia> @btime f(5,4,6)
  0.017 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![konkam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/konkam/32/6598_2.png) [@konkam](https://discourse.julialang.org/u/konkam)\
**Post date:** [January 16, 2019, 4:48pm UTC](https://discourse.julialang.org/t/work-around-splatting-to-avoid-unecessary-allocations/19708/3 "2019-01-16T16:48:19Z")

</div>

Solved, many thanks for looking into it !

I had to remove the slurping `...` for argument x to get the same interface as my original function, but the solution works.

Any idea why the generator allocates but `map` does not ?

Actually, leaving the type constraint on the arguments of the function produces 2 allocations, any idea why ?

```julia
f2(x::Union{AbstractArray{U, 1}, Tuple}) where U <: Integer = Base.Iterators.product(map(N -> 0:N, x)...)
f2 (generic function with 1 method)

@btime f2($(5,4,6))
  23.354 ns (2 allocations: 96 bytes)
Base.Iterators.ProductIterator{Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}}}((0:5, 0:4, 0:6))

```
