Function Repository Resource:

NestedCatch

Source Notebook

Propagate a Throw upward to the outermost NestedCatch

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["NestedCatch"][expr]

catches the first evaluation of Throw[e] and propagates it to the next enclosing NestedCatch if available.

ResourceFunction["NestedCatch"][expr,form]

returns Throw[value,tag] if there is an enclosing NestedCatch ready to catch form, and otherwise returns value from the first Throw[value,tag] for which form matches tag.

ResourceFunction["NestedCatch"][expr,form,f]

returns f[value,tag].

Details and Options

ResourceFunction["NestedCatch"][expr,] always returns the value of expr if no Throw was generated during the evaluation.
The value for form can be any expression and is often a pattern.
In Throw[value,tag], the tag is reevaluated every time it is compared to form.
A Throw that is caught by Catch will not be propagated to any enclosing ResourceFunction["NestedCatch"].

Examples

Basic Examples (3) 

Exit to the enclosing NestedCatch as soon as the Throw is evaluated:

In[1]:=
ResourceFunction["NestedCatch"][Echo[a]; Throw[Echo[b]]; Echo[c]]
Image
Image
Out[1]=
Image

When nested, the Throw propagates upward to the outermost NestedCatch:

In[2]:=
ResourceFunction["NestedCatch"][
 Echo[a];
 ResourceFunction["NestedCatch"][Echo[b]; Throw[Echo[c]]; Echo[d]];
 Echo[e]
 ]
Image
Image
Image
Out[2]=
Image

Compare to Catch:

In[3]:=
Catch[
 Echo[a];
 Catch[Echo[b]; Throw[Echo[c]]; Echo[d]];
 Echo[e]
 ]
Image
Image
Image
Image
Out[3]=
Image

Define a function that can "throw an exception", but will catch its own Throw if necessary:

In[4]:=
f[x_] := ResourceFunction["NestedCatch"][
   If[x > 10, Throw[overflow], x!]];
In[5]:=
f[10]
Out[5]=
Image
In[6]:=
f[11]
Out[6]=
Image

With no outer NestedCatch, the individual values are returned:

In[7]:=
Table[Echo[f[i]], {i, 3, 15, 3}]
Image
Image
Image
Image
Image
Out[7]=
Image

Wrap in an additional NestedCatch so that the Throw will propagate to the top level:

In[8]:=
ResourceFunction["NestedCatch"][Table[Echo[f[i]], {i, 3, 15, 3}]]
Image
Image
Image
Out[8]=
Image

The Throw only propagates upwards to the outermost NestedCatch; the usual Catch is unaffected:

In[9]:=
Catch[Table[Echo[f[i]], {i, 3, 15, 3}]]
Image
Image
Image
Image
Image
Out[9]=
Image
In[10]:=
g[x_] := If[x > 10, Throw[overflow], x!]
In[11]:=
ResourceFunction["NestedCatch"][
 Table[Catch[Echo[g[i]]], {i, 3, 15, 3}]]
Image
Image
Image
Out[11]=
Image

Scope (5) 

The outermost enclosing NestedCatch catches the Throw:

In[12]:=
ResourceFunction[
 "NestedCatch"][{ResourceFunction["NestedCatch"][{a, Throw[b], c}], d,
   e}]
Out[12]=
Image

Compare to Catch, where the nearest enclosing Catch catches the Throw:

In[13]:=
Catch[{Catch[{a, Throw[b], c}], d, e}]
Out[13]=
Image

NestedCatch picks up the first Throw that is evaluated:

In[14]:=
ResourceFunction["NestedCatch"][{Throw[a], Throw[b], Throw[c]}]
Out[14]=
Image

A function that can throw a number of different exceptions:

In[15]:=
f[x_] := Which[
  x < 0, Throw[x, error[negative]],
  x == 0, Throw[x, error[zero]],
  True, 1/Sqrt[x]]

A handler for the possible exceptions:

In[16]:=
handler = Function[{value, tag}, tag /. {error[negative] :> Indeterminate, error[zero] :> Infinity, _ :> Throw[value, tag]}];
In[17]:=
ff[x_] := ResourceFunction["NestedCatch"][f[x], error[_], handler]
In[18]:=
ff /@ {-2, -1, 0, 1, 2, 3}
Out[18]=
Image

Propagate a particular exception upwards with an outer NestedCatch:

In[19]:=
fff[xs_List] := ResourceFunction["NestedCatch"][ff /@ xs, error[zero], Print["zero is forbidden"] &]
In[20]:=
fff[{-2, -1, 0, 1, 2, 3}]
Image
In[21]:=
fff[{-2, -1, 1, 2, 3}]
Out[21]=
Image

The inner NestedCatch catches the Throw:

In[22]:=
ResourceFunction["NestedCatch"][
 b[ResourceFunction["NestedCatch"][Throw[a, u], u]], v]
Out[22]=
Image

The outer NestedCatch catches the Throw:

In[23]:=
ResourceFunction["NestedCatch"][
 b[ResourceFunction["NestedCatch"][Throw[a, u], v]], u]
Out[23]=
Image

As long as the tag matches the form being caught, the Throw will continue to propagate upwards:

In[24]:=
ResourceFunction["NestedCatch"][
 c[ResourceFunction["NestedCatch"][
   b[ResourceFunction["NestedCatch"][Throw[a, u], u]], _]], v]
Out[24]=
Image

Applications (2) 

Write a set of functions that each handle errors at the top level:

In[25]:=
RealSquareRoot[x_] := With[{r = ResourceFunction["NestedCatch"][rsqrt[x]]}, r /; checkResult[r, RealSquareRoot]];
RealSquareRoots[list_List] := With[{r = ResourceFunction["NestedCatch"][RealSquareRoot /@ list]}, r /; checkResult[r, RealSquareRoots]];
In[26]:=
General::nnarg = "The argument `1` is not greater than or equal to zero.";
rsqrt[x_] := If[TrueQ[x >= 0], Sqrt[x], Throw[fail[x, "nnarg"]]];
checkResult[fail[x_, tag_], s_] := Message[MessageName[s, tag], x];
checkResult[_, _] := True;

Since the Throw propagates to the top, only one message is printed for each top-calling function:

In[27]:=
RealSquareRoot[5]
Out[27]=
Image
In[28]:=
RealSquareRoot[-5]
Image
Out[28]=
Image
In[29]:=
RealSquareRoots[Range[5]]
Out[29]=
Image
In[30]:=
RealSquareRoots[-Range[5]]
Image
Out[30]=
Image

Version History

  • 1.0.0 – 20 May 2020

Related Resources

License Information