If the passed function in apply isn't a variadic function, apply will fall back to .apply. This is done for: All JS functions, data structures and single arity CLJS functions.
.apply isn't actually that fast, and in addition we already iterate through the entire sequence because of to-array call.
The effect is particular dramatic on data structures since the .apply call currently goes like this:
1. .apply of the data structures prototype
2. .call dispatcher of the data structures prototype
3. .call IFn of the data structures prototype
4. Finally to .-cljs$core$IFn$_invoke$arity$x
Instead of first iterating over the passed sequence (done in to-array) and then handing it to .apply, we should instead use a very similar approach as to what apply-to helper function does.
Care must be taken to not just call the functions like apply-to does, but instead, if the IFn interface is not found it should call the function with f.call(f, arg0, arg1, ....); which is the way the .apply currently calls functions.
This solves both performance issues, ie, also avoiding the slow calling of data structures by avoid the above steps.
Should we re-use apply-to and introduce a parameter to call the function differently? Or should we create a second function similar to apply-to?
By simple using apply-to instead of .apply call in apply we can improve the performance by around 300-400% across browsers. This is for all kinds of functions, single arity functions (equal to JS functions), multi arity functions, and data structures.