5
$\begingroup$

I have some packages/scripts that I schedule the execution using Jobs in SQL server. For example, in some of then, I use to create reports and delivery by mail using Mathematica. All done using command line execution, without front end. Some times I have an unexpected problem in the middle of the code, and I would like abort the execution, maybe create some log file if it happens in a txt (all before send the mail, to abort the delivery, or delivery just to me a error msg). I would like to know what is the best practice to do that in Mathematica. I'm used to break my code in blocks, so I can handle that. Today I use Check in each block, with some message in the second argument followed by Quit[].

someCodeBock//Check[#, Print["error msg"];Quit[]]&

Is this the best way? There is some difference between Exit and Quit? In VB I use on error goto X.

$\endgroup$
1
  • $\begingroup$ If you need it, you can use Internal`addHandler to handle the message as soon as it is printed. I use this to dump a stack trace to a new file and put a line in my log file indicating where the stack trace is. See mathematica.stackexchange.com/questions/1512/… $\endgroup$ Feb 11, 2013 at 1:46

1 Answer 1

8
$\begingroup$

Generally, it is better to use softer than harder error-reporting mechanisms. Calling Quit[] seems too radical to me. What normally happens is that functions where the error occur are not in the position to make right decisions about what to do with the error, since they are likely too low-level. This is exactly the reason why exceptions exist. They (exceptions) are used to propagate the error up the execution stack to those functions which are in a position to make such decisions.

In your case, this seems to be a problem because in a simple script, two different stages are mixed together - definition-time and run-time. This is because script execution is single-pass, so it reads and executes code at the same time. What you can do to avoid this is to create functions which would compute the things you need, and store them in a separate file (package), and make your script read them in at the start. Equivalently, you can define all those functions at the start of your script. The idea is that you have just a single function to execute, so that a script can look like

f1[x_,y_,...]:=...
f2[x_,y_,z_,...]:=...
...
fn[x_]:=...

you can define those functions so that each of them throws an exception in case of some error, such as

f1[x_,y_]:= 
  Module[{},
    some computation;
    If[error, Throw[$Failed, MyException[f1,{x,y}]]]
    some more computation;
    result]

Then basically the main function looks like

myMainFunction[x_,y_,z_,...]:=
  Catch[
    Module[{a},
     a = f1[x,y];
     f2[x,f3[a],z];
     ...
    ],
    _MyException,
    handlerFunction
  ];

and the actual computation looks like

myMainFunction[my-starting-parameters];

Quit[]

The handlerFunction in your main function can do different things depending on where the problem happened and what it was, but at least in this way you have a separation between the computation and the error-handling, and a much softer way to handle errors than if you call Quit[].

This is not specific to Mathematica. It is the same logic as in e.g. C, where you won't ordinarily put lots of exit(EXIT_FAILURE) in your code - at least this is considered a bad style. The biggest problem with this approach is that you don't give a chance for your higher-level functions to consider the problem and perform certain finalizing or recovery actions which may be needed to gracefully exit in the case of error.

$\endgroup$
9
  • $\begingroup$ One thing to note when using this strategy is that you should deal with the error at the lowest level you possibly can, simply because there is no resume mechanism. In other words, once the error escapes a level, it can't return. This is the quandary often faced when dealing with c++ exceptions. So, if you can deal with it in place, then do so, and only pass up if needed. A method is to create a set of handlers that the low-level functions can call when they encounter issues, and throw from within them, if it must be passed up the chain. $\endgroup$
    – rcollyer
    Feb 8, 2013 at 20:06
  • $\begingroup$ (cont'd) of course, that makes the low-level code dependent on the error handlers ... $\endgroup$
    – rcollyer
    Feb 8, 2013 at 20:07
  • $\begingroup$ @rcollyer Well, when I was dealing with exceptions during my work in industry with Java (a typical project would be more than a thousand classes), the standard way is to subclass exceptions to have specific exception types for various error cases. Those exceptions are just thrown from whichever function encounters the error, without any additional wrappers - there is no need for them. What is really important is modular design and right API design, and specific exceptions which can be thrown by various methods are part of the API specs. What you do with the error is application-specific. $\endgroup$ Feb 8, 2013 at 20:11
  • $\begingroup$ @rcollyer In other words, most important is the right separation between different modules, and loose coupling. Besides, the developers of a given module have to make sure that they do all the clean-up work so that exceptions they throw don't leave their module in some invalid state. There is a big debate which exceptions must be checked (compile-time) and which must be run-time, here there are different opinions. I personally think that checked exceptions are good because this is documented in method's signatures, although some exceptions should be run-time. $\endgroup$ Feb 8, 2013 at 20:16
  • $\begingroup$ Absolutely. I was just placing a warning when dealing with any thing thrown: you can't go back. So, think about the design, so that you are able to resume, if need be. In other words, "modularity" as you put it. My intent was to warn novices about it, as it isn't immediately obvious how to deal with it. $\endgroup$
    – rcollyer
    Feb 8, 2013 at 20:19

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.