I've seen people compare Block
with Module
and With
as scoping constructs, and try to figure out when to choose which. Also, I've seen posts about Function
versus #
versus downvalue functions.
However, I already understood the differences between those, but still find myself more often doubting between functions and With
...
Does With
have any advantage in any case over Function
?
I am talking about this constructions
With[{sth=inj}, code code sth code]
versus
(code code # code)&[inj]
or
Function[sth, code code sth code][inj]
Apart from the fact that its syntax is better suited for defining constants since the variable name and value are "together", or other elegance issues I mean.
They are both scoping constructs, and Function
among other uses can also inject code as With
. If With
's variables are set with :=
you can always use Function
version with attributes.
I know, this doesn't hold in the infrequent situation when you would use a With
with, e.g, 2 :=
s and 2 =
s which can't be emulated by a function attribute.
In the (not so extensive) tests I've done it doesn't seem to be faster.
In[127]:= TimingAverage[
With[{sum = 2 + 8},
{sum*x, sum*y}]]
Out[127]= 3.42178*10^-6
In[124]:= TimingAverage[
Function[{sum}, {sum*x, sum*y}][2 + 8]
]
Out[124]= 3.36266*10^-6
In[122]:= Module[{lalala},
lalala[sum_] := {sum*x, sum*y};
TimingAverage[
lalala[2 + 8]
]
]
Out[122]= 2.88582*10^-6
In[123]:= TimingAverage[
{#*x, #*y} &[2 + 8]
]
Out[123]= 2.67792*10^-6
Just out of curiosity, this very same test seem to be consistent with the common knowledge of Module
being slower than Block
being slower than With
In[119]:= TimingAverage[
Module[{sum = 2 + 8},
{sum*x, sum*y}]]
Out[119]= 7.19833*10^-6
In[120]:= TimingAverage[
Block[{sum = 2 + 8},
{sum*x, sum*y}]]
Out[120]= 4.58145*10^-6
As to the holding version of the tests, we get marginally better results with With
In[129]:= TimingAverage[
Function[{sum}, {sum*x, sum*y}, HoldFirst][2 + 8]
]
Out[129]= 4.22668*10^-6
In[128]:= TimingAverage[
With[{sum := 2 + 8},
{sum*x, sum*y}]]
Out[128]= 3.8681*10^-6
In[131]:= Module[{lalala},
SetAttributes[lalala, HoldFirst];
lalala[sum_] := {sum*x, sum*y};
TimingAverage[
lalala[2 + 8]
]
]
Out[131]= 3.45039*10^-6
EDIT
As to style and elegance, I guess that functions are more suited when the expressions you're injected are big and the code you're injecting them into is small, and With
otherwise.
Any thoughts on all this issue? Am I missing something?
With[{x=1,n=2}, x^n]
vsFunction[{x,n}, x^n][1,2]
. InFunction
the "constants" (i.e.x
andn
) are named at the beginning, at set at the end without their name being mentioned. This is a significant usability disadvantage when you just want to put inject a number of expressions into code. Otherwise I think there's no behavioural difference between them for the use you mention. $\endgroup$