Which is better for optimizing speed, memory, and coding "safety" – passing arguments to a function or passing a list to the function and call the list's parts?

That is, which of the following gives better performance?

f[#1, #2, ..., #n] &[x1, x2, ..., xn]


f[#[[1]], #[[2]], ..., #[[n]]] &[{x1, x2, ..., xn}]

Both, of course, give the same output...


Assume f is complicated enough and n is large enough for any performance differences to be significant.

  • $\begingroup$ Well, it seems like neither of these methods would work in practice—the syntax is not correct, per my understanding—but assuming you want to use some similar variation of this, I would point out that in either case, you’ll need to know in advance how many n arguments there will be, which may cause some issues in the future that would be avoided by generalizing the method to not require advanced knowledge of what n is. $\endgroup$ Jul 17 '21 at 2:11
  • 2
    $\begingroup$ @CATrevillian Do you mean the …’s? I know that syntax is technically not correct, but I thought context made the meaning obvious. $\endgroup$ Jul 17 '21 at 2:35
  • 1
    $\begingroup$ f@@{x1,x2,…,xn} ? $\endgroup$
    – cvgmt
    Jul 17 '21 at 7:58
  • $\begingroup$ Related but different question mathematica.stackexchange.com/q/251146/12697 $\endgroup$ Jul 18 '21 at 4:11

In the following simplistic benchmark, passing a single argument-list g[{x1,x2,x3,...,xn}] is about 100×–1000× faster than passing arguments separately f[x1,x2,x3,...,xn] when using large numbers of arguments:

f[x__] := Total[{x}]     (*  slow: call as f[x1,x2,x3,...,xn]    *)
g[x_]  := Total[x]       (*  fast: call as g[{x1,x2,x3,...,xn}]  *)

a = RandomReal[{0, 1}, 10^6];

f @@ a // AbsoluteTiming
(*    {0.17291, 499561.}    *)

g @ a // AbsoluteTiming
(*    {0.000386, 499561.}    *)

It appears that calling g is limited by the actual calculation of Total, whereas calling f is limited by the pattern-matching overhead.

  • $\begingroup$ Wouldn’t this analysis be particular to the function ‘Total’? $\endgroup$ Jul 18 '21 at 4:28
  • $\begingroup$ I don't think so. Total is extremely fast and does not present a bottleneck here. If you don't believe it, you can replace Total with some other function and benchmark again. $\endgroup$
    – Roman
    Jul 18 '21 at 4:53
  • $\begingroup$ Good example. But there may be use cases where the list arg would require dereferencing individual elements. In such cases, if the input is not a packed array it might be faster to not use the list form. $\endgroup$ Jul 18 '21 at 15:48
  • $\begingroup$ @DanielLichtblau I would assume that the f-form dereferences every argument by default, and so would be even slower when applied to a non-packed array, irrespective of any dereferencing happening inside the function call. Or do you have a concrete example in mind where f would be faster than g? $\endgroup$
    – Roman
    Jul 19 '21 at 13:06
  • $\begingroup$ In the f form there is no list to dereference. That said, I might try to create an example when I have access to my desktop machine (next week). $\endgroup$ Jul 19 '21 at 16:48

Essentially you are asking if

Function[{x1, x2}, f[x1, x2]] [x1, x2]

is better in some sense than

Function[x, f[x[[1]], x[[2]]]]@ {x1, x2}

with respect to optimizing speed, memory, and coding "safety". With regard to speed and memory, it is possible to test performance with controlled experiments. With regard to coding "safety", that is a matter of opinion and taste. Without some specific details I do not think it is possible to give an appropriate answer.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.