Hello,
in this example of code:
f1[x_] := Return[x + 1];
f2 := Function[{x}, Return[x + 1]];
f1[1] returns “2”, but f2[2] returns “Return[2]”. Why doesn’t the Return[] operator work correctly in the second function?
Hello,
in this example of code:
f1[x_] := Return[x + 1];
f2 := Function[{x}, Return[x + 1]];
f1[1] returns “2”, but f2[2] returns “Return[2]”. Why doesn’t the Return[] operator work correctly in the second function?
Actually f2[2] returns “Return[3]”. Don’t use “Return” in a pure function, write
f2 := Function[{x}, x + 1];
Now f2[2] returns 3.
OK, so these two ways of functions declaration aren’t equivalent.
And a more general statement is never to use Return anywhere in your Mathematica programs. (Nor use Label, Goto, or other ancient approaches to flow control–they are in Mathematica for those who are coming from old programming paradigms, but are strongly recommended against.) If you need to leave a program flow prematurely use Throw and Catch or in some cases Sow and Reap. Remember that Mathematica returns the last evaluation in a CompoundExpression (i.e., a sequence of commands separated by semicolons) so long as the final command is not ended with a semicolon.
This is some useful reading: http://mathematica.stackexchange.com/q/29353/12
While Return is very rarely needed, I think it’s quite useful in situations like
f[...] :=
Module[{...},
...
If[error, Message[f::err]; Return[$Failed]];
...
If[otherError, Message[f::err]; Return[$Failed]];
...
result
]
(since this can be such a common pattern)
Actually I always use
f[...] :=
Catch@Module[{...},
...
If[error, Message[f::err]; Throw[$Failed]];
...
If[otherError, Message[f::err]; Throw[$Failed]];
...
result
]
in those cases
. Part of the reason is just habit, but also it allows me to control exactly where the Throw gets caught without any ambiguity. And one can use tags in appropriately palced Throws and Catches if a more complex logic is needed.
Well, that has its dangers too.
Consider this toy example:
In[5]:= SetAttributes[f, HoldAll]
f[x_] := Catch@Module[{}, If[x < 0, Throw[$Failed]]; Sqrt[x]]
In[7]:= f[-1]
Out[7]= $Failed
In[8]:= f[2]
Out[8]= Sqrt[2]
In[9]:= f[Throw[boo]; 2]
Out[9]= boo
The same caveat applies to Sow/Reap.
This can be fixed by using a (private) tag with Throw and Catch (or Sow and Reap).
Ah yes, code that takes code in its argument. One might like to think that things like that are exceptional cases, but that isn’t necessarily so for many of the things one might want to do with Mathematica. So this sort of thing is very worth remembering when one finds behavior that seems “buggy” in code that one has written that processes code–and such cases will invariably have Hold* attributes or make use of Unevaluated and things like that…
OK, so these two ways of functions declaration aren’t equivalent.
This is exactly true: these are completely different constructs. Strictly speaking, there are no “function declarations” in Mathematica (in the C language sense). Mathematica has global replacement rules and pure functions.
When you evaluate
f[x_]:=x^2
you define a global replacement rule which replaces each occurrence of an expression which matches f[x_] with x^2.
When you evaluate
f=#^2&
or
f=Function[x,x^2]
you define a global replacement rule which replaces each occurrence of f with Function[#,#^2] or Function[x,x^2] accordingly. The Function has its own logic of evaluation.