# Splatting arguments causes ~30x slow down

**URL:** https://discourse.julialang.org/t/splatting-arguments-causes-30x-slow-down/16964
**Category:** Performance
**Tags:** development
**Created:** [October 30, 2018, 12:36pm UTC](https://discourse.julialang.org/t/splatting-arguments-causes-30x-slow-down/16964 "2018-10-30T12:36:44Z")
**Posts on this page:** 1
**Showing post:** 2

<div class="post-metadata">

### Author: ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)
#### Post date: [October 30, 2018, 4:00pm UTC](https://discourse.julialang.org/t/splatting-arguments-causes-30x-slow-down/16964/2 "2018-10-30T16:00:17Z")

</div>

Great question! You are running up against the specialization heuristics of the compiler: basically, the question is “should Julia compile a specialized version of every single function for every single argument combination?” In some cases that’s counterproductive, so at a certain point Julia’s compiler decides to punt and use runtime dispatch.

Here you have two challenges to specialization:

- splatting
- the `f` argument (which is an arbitrary function)

To be clear, to get ideal performance it has to compile a separate version for every combination of `args` types and for every different `f`, and in this case either one is enough on its own to prevent specialization (especially because `f` is being called varargs, that might not happen in other cases). Consequently, you have to “solve” both problems to see great performance.

The following modifications suffice for me:

```julia
function apply4!(f::F, y, args::Vararg{T,N}) where {F,T,N}
    for i in eachindex(args[1])
        y[i*2 - i%2] = _map_i(f, i, args...)
    end
    return y
end

@inline _map_i(f::F, i, x1) where F = f(x1[i])
@inline _map_i(f::F, i, x1, x2) where F = f(x1[i], x2[i])
@inline _map_i(f::F, i, x1, x2, x3) where F = f(x1[i], x2[i], x3[i])
@inline _map_i(f::F, i, x1, x2, x3, x4, args...) where F = f(x1[i], x2[i], x3[i], x4[i], getindex.(args, i)...)

```

I did two things here:

- the `f::F` syntax seems useless, but it turns out to force specialization on the function argument
- the `::Vararg{T,N}` forces it to specialize the function for all different numbers of input arguments.

With these two changes I get the same performance from `apply4!` that I get from `apply1!` and `apply2!`.

This might be more intuitive if we had a `@specialize` macro, so that one could write

```julia
function apply4!(@specialize(f), y, @specialize(args...))
    ...
end

```

---

_[View the full topic](https://discourse.julialang.org/t/splatting-arguments-causes-30x-slow-down/16964)._
