2

I like to write functions that dispose of failure cases early, before they do the main calculation, but I don't like to write cascading If statements. Here is a toy example of the sort of function I mean:

f[x_] :=
  Block[{$TooBig},
    If[! NumericQ[x], Return[$Failed]];
    If[x > 10, Return[$TooBig]];
    x!]
f /@ {5, 11, "x"}
 {120, $TooBig, $Failed}

Now suppose rather than define f, I would like to use a pure function, so I write

Block[{$TooBig},
  If[! NumericQ[#], Return[$Failed]];
  If[# > 10, Return[$TooBig]];
  #!] & /@ {5, 11, "x"}
{120, Return[$TooBig], Return[$Failed]}

The pure function returns at the appropriate points for all three arguments, but in the cases where Return should be called, it is returned unevaluated. I did not expect this behavior. Is it a bug or have missed a something I should be aware of?

I will point out that I do know how to work around this difficulty.

Block[{$TooBig},
  If[! NumericQ[#], Return[$Failed, Block]];
  If[# > 10, Return[$TooBig, Block]];
  #!] & /@ {5, 11, "x"}
 {120, $TooBig, $Failed}

I'm running V.10.2 on my system and don't have access to any older versions of Mathematica, so I don't know if this a version specific problem.

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
  • 1
    Duplicate? http://mathematica.stackexchange.com/q/29353/12 – Szabolcs Sep 04 '15 at 15:40
  • @Szabolcs. Sure looks like one. – m_goldberg Sep 04 '15 at 15:51
  • Some might argue that this is bad style, or that one should really use Throw/Catch, but the behaviour you observe can actually be exploited: check = If[Not@NumericQ[#], Return[$Failed]] &; then fun[x_] := Block[{}, check[x]; x^2 ]. Suppose you have lots of functions like fun (I do) and you want to avoid re-typing the same sorts of argument checks. – Szabolcs Sep 04 '15 at 15:57
  • Since it is not explicitly mentioned, Return[value, Block] solves the problem: Block[{$TooBig}, If[! NumericQ[#], Return[$Failed, Block]]; If[# > 10, Return[$TooBig, Block]]; #!] & /@ {5, 11, "x"} – user8074 Sep 04 '15 at 16:03
  • 2
    @user8074. It is most certainly explicitly mentioned. – m_goldberg Sep 04 '15 at 16:05
  • @m_goldberg I cannot find Return[...,Block] either in mathematica.stackexchange.com/q/29353/12 or in MMA9 help. Where is it explicitly mentioned? – user8074 Sep 04 '15 at 16:13
  • @user8074 In this question itself – Leonid Shifrin Sep 04 '15 at 16:17
  • @Szabolcs I'd argue that the opposite is true: using Throw / Catch is a bad style when Return (with 2 args, may be) can be used. Of course, one must know how to use it correctly, and it is not very intuitive at first. – Leonid Shifrin Sep 04 '15 at 16:20
  • @LeonidShifrin Right! Now I saw it: temporary blindness :). But it is not a duplicate: this solution is not reported elsewhere and works also on previous versions (9, for example). – user8074 Sep 04 '15 at 16:34
  • @user8074 The way question is currently posed, it is a duplicate, because the OP was interested in the explanation of the behavior, rather than a solution (of which he was aware). But I'd agree with you that it would be more useful for the site in general, if the question was "how would I use Return in this case ...", and then it would not be a direct duplicate. – Leonid Shifrin Sep 04 '15 at 16:42
  • @user8074 Actually the answer to the other question also mentions the two-argument form of Return. – Szabolcs Sep 04 '15 at 16:45
  • @Szabolcs, premitting that I fully understood Leonid's reply and agree, the two-argument form of the previous answers mentions only CompoundExpression, which is not normally used explicitly, while Block is a common language costruct. Consequently Return[..., Block] deserves an explict mention in my opinion. – user8074 Sep 04 '15 at 16:58
  • @user8074 Why don't you post a question and answer it yourself? It would be quite useful. – Szabolcs Sep 04 '15 at 16:59
  • @user8074 If you go on and ask the question / self-answer, keep in mind that this is not specific to Block - the same happens also in the case of With or Module. So, I'd rather formulate it as "how would one return from some place of the pure function's body, using Return". In fact, when there is no scoping construct but one wants to return from p.f. using Return, a useful trick is to wrap the body of p.f. in an idle Module[{}, ...] or similar - which would then allow to use Return[..., Module]. I've been using this trick many times. – Leonid Shifrin Sep 04 '15 at 17:13

0 Answers0