7
$\begingroup$

There are lots of question/answers about exception handling in Mathematica. I still find exception handling in Mathematica too complicated to work with.

I find Maple much simpler and easier to understand when it comes to exception handling.

What would be the simplest translation of the following code from Maple to Mathematica?

foo:=proc(x,y)
   try
      x/y;
   catch:
      error "I give up, bad input";
   end try;
end proc;

The above defines a function foo. The main exception handling is done using try .... catch: ... end try

The call to error terminates the function sends an error message to the caller (if any).

The use of : after catch means to catch ANY error. (otherwise one can catch specific error.

So when calling the above in Maple this is the result

Mathematica graphics

And when calling it as foo(1,1) no error is generated.

I do not want to set separate functions and define external message string and tags and so on in Mathematica to do the above as shown in Error checking and trapping techniques with Throw and Catch for example which is very good but I find hard to follow and more complicated than in Maple. I'd like everything done inside the Module

The try .. catch... end try is much simpler to use and understand.

What is the simplest way to implement similar code as the above Maple function?

$\endgroup$
1
  • $\begingroup$ I was waiting to see how you would respond to Roman's answer as it seems to me the natural approach, if I understand the question. Since you did not I guess I'll ask, what's wrong with it? $\endgroup$
    – Mr.Wizard
    Mar 2, 2020 at 9:50

3 Answers 3

4
$\begingroup$

You could do

f[x_, y_] := Check[x/y, $Failed]

f[1, 0]

During evaluation of Power::infy: Infinite expression 1/0 encountered.

$Failed

In this way you can pass the $Failed to the caller and react to it, instead of passing the default of ComplexInfinity (which is useful in its own way).

$\endgroup$
4
$\begingroup$

Maybe something like this?

f[x_, y_] := Module[{}, Quiet@Check[x/y, Throw["I give up, bad input"]]];

f[1, 0]
(* Throw::nocatch : Uncaught Throw[I give up, bad input] returned to top level. *)
$\endgroup$
2
  • $\begingroup$ Thanks., but it seems the error do not get cought by caller. i.e. When I tried g[x_, y_] := Module[{},Check[f[x, y], Throw["f[x,y] threw an error !"]]]; I was expecting to see the error f[x,y] threw an error ! but instead got the error I give up, bad input. Which tells me the throw from f[x,y] goes directly to top level bypassing the caller. $\endgroup$
    – Nasser
    Feb 29, 2020 at 3:39
  • $\begingroup$ The caller can wrap the called function in Catch to stop propagation to the top level and handle it as needed. Have you tried that? $\endgroup$ Feb 29, 2020 at 4:34
3
$\begingroup$

Here's a simple way to do that. First define something to validate your output and which will Throw a tag if invalid. Then Catch that:

validateResp // Clear
validateResp[resp_, validator_, error_: Automatic] :=
  If[! TrueQ[validator@resp],
   Throw[resp, Replace[error, Automatic :> $tryCatchTag]],
   resp
   ];
tryCatch // Clear
SetAttributes[tryCatch, HoldFirst];
tryCatch[
  expr_,
  error : _String | Verbatim[Blank][] : "BadValue",
  handler : Except[_String | Verbatim[Blank][]] : (#2 &),
  validator : Except[_String | Verbatim[Blank][]] : (Length[$MessageList] == 0 &)
  ] :=
 Block[{$tryCatchTag = error},
  Catch[
   validateResp[expr, validator, error],
   error,
   handler
   ]
  ]

You'd use it like this:

tryCatch[
 1/0
 ]

(* Message: Power::infy: Infinite expression 1/0 encountered. *)

(* Out: "BadValue" *)

Unfortunately there's no global sense of "if an error occurred" so by default my validator just checks if any messages were generated when evaluating, but this can be anything. You can also put a deeper validateResp in there if you want. You can also easily throw your own errors and catch anything like:

tryCatch[
 If[! TrueQ[n > 2],
   validateResp[False, False &, "BadN"],
  1/0
  ],
 _
 ]

"BadN"

Which if the first test passed would give you

tryCatch[
 If[False,
   validateResp[False, False &, "BadN"],
  1/0
  ],
 _
 ]

(* Message: Power::infy: Infinite expression 1/0 encountered. *)

(* Out: _ *)
$\endgroup$
3
  • $\begingroup$ Thanks. But this is still way more complicated than Maple's :). But it does work. $\endgroup$
    – Nasser
    Feb 29, 2020 at 3:41
  • $\begingroup$ @Nasser yeah it’s a different language so it’ll have different error handling semantics. Inescapable product of the flexibility of the language $\endgroup$
    – b3m2a1
    Feb 29, 2020 at 3:43
  • 1
    $\begingroup$ yes, ofcourse. Sometimes I think Mathematica is way "too flexible" with the side effects it can become "too complicated" as well. $\endgroup$
    – Nasser
    Feb 29, 2020 at 3:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.