3
$\begingroup$

Question: Why does this fail?

In:= (Catch[#] &)[Throw[17]]
Throw::nocatch : Uncaught Throw[17] returned to top level. >>
Out= Hold[Throw[17]]

These other functional forms also fail:

  1. Function[{x}, Catch[x]][Throw[17]]
  2. jCatch[x_] := Catch[x]; jCatch[Throw[17]]

Background

I recently wasted time tracking down an error from Return[]'s nonintuitve behavior (It doesn't breaks from For loops but does from Do loops!?). So I tried to replace the Return in a function with Throw and Catch. I had been advised that it's never good idea to use these without tags, but I don't like having the tag for Catch all the way at the bottom of the function because this makes it harder, when looking at a given Throw, to locate the corresponding Catch.

f[x_]:=Catch[
  ...
  ...
  If[y<z,Throw[a,"tag"];
  ...
  ...
  Throw[b,"tag"];
 ,"tag"];

Maybe I'm unreasonable, but I'd rather have the tag at the beginning. So I tried

f[x_]:=(Catch[#,"tag"]&)[
  ...
  ...
  If[y<z,Throw[a,"tag"];
  ...
  ...
  Throw[b,"tag"];
 ];

But this fails as explained above.

Is there a way to get the tag at the front of the code rather than end? Is there another construct I should be using instead? I hear people bad-mouth nonlocal code jumps, but what's the alternative here, putting the entire rest of the function in the 'else' parameter of the If statement?

$\endgroup$
  • 1
    $\begingroup$ Function[{x}, Catch[x], HoldAll][Throw[17]] works, tho. $\endgroup$ – J. M. will be back soon May 29 '16 at 13:50
  • $\begingroup$ Thanks much, this answers my main question. Now I can use jCatch = Function[{tg,x}, Catch[x,tg], HoldAll]; and define a function as f[x_]:= jCatch["tag", ... Throw[a, "tag"]];. Can you explain what's going on here? I see that it must be closely related to the fact that Catch[Evaluate[Throw[17]]] gives an error, but I don't see why. What does it mean that the Throw is "returned to the top level" when it's obviously surrounded by the Catch? $\endgroup$ – Jess Riedel May 29 '16 at 14:00
  • 1
    $\begingroup$ The Throw[] isn't supposed to evaluate unless there's an enclosing Catch[]. Catch[Evaluate[Throw[17]]] has the Throw[] evaluate before being seen by Catch[], leading to your observed behavior. Another one for your notes: Function[Null, Catch[##], HoldAll][Throw[17]]. $\endgroup$ – J. M. will be back soon May 29 '16 at 14:07
  • $\begingroup$ How would I define jCatch to accept both (a) one argument (the tag) and return a single argument function Function[{exp},Catch[exp,tag],HoldAll], or alternatively (b) two arguments (the tag and the expression) and return Catch[exp,tag]. I need to define it with Function rather than & or a replacement rule, since I need to use HoldAll. And (it seems) I need to use named arguments (Function[{tag,exp},...]) because I want to return a function (i.e., I'll have nested function ). $\endgroup$ – Jess Riedel May 29 '16 at 15:03
  • $\begingroup$ Did you try the last snippet in my previous comment? $\endgroup$ – J. M. will be back soon May 29 '16 at 15:07
2
$\begingroup$

I agree that behavior of Return with one or no arguments can be unintuitive, but usage of Return with two arguments, where second argument is head of expression you want to return from, is pretty straightforward.

ClearAll[f]
f[x_] :=
    Module[{a = x},
        (*...;*)
        If[a < 5, Return[a, Module]];
        (*...*)
        a + 1000
    ]

f[2]
(* 2 *)
f[x]
(* 1000 + x *)

I use above unless construct, from which I want to return, is nested.


As to Throw/Catch problems.

The Standard Evaluation Procedure of Mathematica is that arguments of functions are evaluated before they are passed to the function. So in (Catch[#] &)[Throw[17]] expression Throw[17] is evaluated before evaluation of Catch starts.

Catch itself has HoldFirst attribute thus is a subject of non‐standard evaluation and in Catch[Throw[17]] expression Throw[17] is evaluated after evaluation of Catch started and caching mechanism was set up.


As already suggested in comments to define you own catching function you must use one of Hold... attributes.

ClearAll[jCatch]
SetAttributes[jCatch, HoldRest]

jCatch[tag_] := Function[expr, Catch[expr, tag], HoldFirst]
jCatch[tag_, expr_] := Catch[expr, tag]

jCatch[tag]@Throw[17, tag]
(* 17 *)
jCatch[tag, Throw[17, tag]]
(* 17 *)

You could also make it a "macro" that will be evaluated, in definition time, to ordinary Catch:

jCatch /: HoldPattern@SetDelayed[lhs_, jCatch[tag_]@expr_] :=
    SetDelayed[lhs, Catch[expr, tag]]
jCatch /: HoldPattern@SetDelayed[lhs_, jCatch[tag_, expr_]] :=
    SetDelayed[lhs, Catch[expr, tag]]


ClearAll[f]
f[x_] := jCatch[tag]@Throw[x, tag]
?? f
(* Global`f
   f[x_]:=Catch[Throw[x,tag],tag] *)
$\endgroup$
2
$\begingroup$

Consider the following contrived example.

chooser :=
  Catch[#, "me"]&[Unevaluated @
    Module[{u = RandomChoice[{1, 2, 3}]},
      Switch[u,
        1, Throw[1, "me"],
        2, Throw[2, "me"],
        3, Throw[3, "me"]]]]

SeedRandom[42]; Table[chooser, 5]

{2, 3, 2, 1, 1}

Does that give you an idea on how you might write your code in a style more compliant to your wishes?

$\endgroup$
  • $\begingroup$ Well, it's different around the problem. (Currently I'm defining jCatch = Function[{tg}, Function[{ex}, Catch[ex, tg], HoldAll], HoldAll]; and then using jCatch@Module[{...}...]. But ultimately the Mathematica evaluation system is still opaque enough that I can't determine easily what's going to work without experimenting. Can you recommend a place to read about it? Also, do most people just use Return and/or Throw, or is there another best practice I should consider? Thank you. $\endgroup$ – Jess Riedel May 29 '16 at 20:42
  • 3
    $\begingroup$ @JessRiedel. I have been programming Mathematica for 19 years and I have found only a few situations where I need to use Return or Catch-Throw constructs. Mathematica's evaluation system is indeed both exotic and complex. I recommend Wagner's Book to those looking to understand it. $\endgroup$ – m_goldberg May 29 '16 at 20:51

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.