18
$\begingroup$

Since version 10 (at least 10.0.2 but I think 10.0.0) there is Failure and since version 10.2 there is also FailureQ. As often the documentation is somewhat vague and says "Failure is generated by Interpreter and related functions.".

To me it looks like Failure is not more than a symbol which can be used as the head of an expression in a return value or an argument to Throw which indicates that something went wrong. A Failure expressions is expected to have two arguments, the first being a tag to be able to match against, the second an association as a second argument which can hold additional information about what went wrong. That is very much what an Exception object in other languages would contain and has obvious applications.

The question is whether it would be a good idea to rely on these symbols for my own code or whether it is more safe to run my own "exceptions" package. I currently don't see any disadvantage of just using Failure in that way which would save me from providing a new symbol in an additional package which creates dependencies and I could also take advantage of an already defined FailureQ and - less important but nice to have - formatting of these failure-expressions.

Any thoughts and experience out there? Any recommendations from WRI known to be published anywhere?

$\endgroup$
  • $\begingroup$ No, FailureQ is not since version 10.0. It's since version 10.x where I don't remember x exactly (probably x=2). If compatibility is important, roll your own FailureQ. I considered using Failure, as there seem to be a few new functions that use it (other than Dataset/Interpreter). But I haven't started using it because I need compatibility with 10.0. I'm not sure how much is missing from 10.0 as FailureQ should be easy enough to replace. $\endgroup$ – Szabolcs Sep 22 '16 at 10:28
  • $\begingroup$ @Szabolcs: Failure is there since 10.0.0, FailureQ since 10.2 (at least that is what the documentation sais...). As for FailureQ I think compatibility is a good point to have in mind, but 10.2 would be good enough for my current purpose and as you suggest would be easy enough to provide for versions < 10.2.... $\endgroup$ – Albert Retey Sep 22 '16 at 10:34
  • $\begingroup$ I don't remember exactly, but I think the reason why I didn't choose to do this was that the transition would have been gradual. I would have had some functions that returned $Failed and some that returned Failure. I would have needed to provide a very clear way for users to test for failure. For v10.0 compatibility I would have had to provide a FailureQ alternative that would be redundant for 10.2. I thought that doing this is too confusing and not user friendly enough. It wasn't a technical reason why I didn't use Failure, it was more about the user experience. $\endgroup$ – Szabolcs Sep 22 '16 at 11:03
  • 3
    $\begingroup$ If 10.2 is your target version, then go ahead and use it and tell your users to test with FailureQ. Failure is nicer than $Failed. I do wish WRI made a push to unify the multitude of ways of error reporting/handling. $\endgroup$ – Szabolcs Sep 22 '16 at 11:03
14
$\begingroup$

What I personally usually do is to still use $Failed / exceptions when a returned $Failed / thrown exception can't be used constructively when handled / caught, other than issuing the right message. In some cases, however, the application logic requires to do more than that. In particular, certain data associated with the state right before the failure may be needed to handle the error correctly. In cases like that, Failure seems a good match.

There are at least two different modes in which Failure can be used. One is that in the case of a failure, you return the Failure object to the calling function, instead of just returning $Failed. This would allow to return not just the fact of the failure, but also error code. Another is to use Throw like

Throw[Failure[...], tag]

combining Failure and exceptions. This is needed in the same situations where exceptions are typically used, but Failure allows us to bring more information along with an exception. Along similar lines, Failure can also be abused constructively to have a non-local control flow, even in cases which aren't hard failures - I did this a few times in inner functions not facing the user.

Surely one can place association inside an exception tag, doing essentially the same:

Throw[$Failed, error[label, assoc]]

or something like that, but I feel that using Failure in cases like this is semantically cleaner.

All in all, I don't see any reason not to use Failure in cases when one needs to bring additional information to the function that must handle the error, be it in return mode or exception mode.

$\endgroup$
  • $\begingroup$ That is basically how I am planning to use it, so your answer gives me some trust it isn't too bad an idea. Have you any insight whether people at WRI consider that as a standard pattern open for others to use or even a welcomed and supported standard (like e.g. options) or rather consider that an internal construct that a user only should know about when it pops up? The documentation doesn't really read like a suggestion to use Failure in own code... $\endgroup$ – Albert Retey Sep 22 '16 at 19:47
  • $\begingroup$ @AlbertRetey AFAIK, Failure is used internally in various projects. And I don't have a feeling that it is considered only as internal tool. I think it should be perfectly fine to use it. $\endgroup$ – Leonid Shifrin Sep 22 '16 at 19:52
  • $\begingroup$ OK, thanks for that information. Of course it would be even nicer when they could decide to encourage the use of Failure more official, but I think I can live with what we have... $\endgroup$ – Albert Retey Sep 22 '16 at 19:59
  • $\begingroup$ @AlbertRetey I actually think that Failure has not been used uniformly also in the company. Some folks use it, some don't. Actually, the percentage of cases when I personally prefer Failure to $Failed or exceptions is fairly small - because in most cases I don't need to pass much additional information about the failure to the error / exception handler. $\endgroup$ – Leonid Shifrin Sep 22 '16 at 20:02
1
$\begingroup$

I made a package called functionArgumentFailure which uses Failure to handle functions which have been called with wrong arguments.

   Needs["functionArgumentFailure`"]

   ClearAll[test];

   test[a_?StringQ] := 1;
   test[args___] := functionArgumentFailure[test, args]; 

Here is an example where the function test has been called with not enough arguments:

enter image description here

I think Failure is a nice way to give feedback about what went wrong, it can be much more informative than a message. It might also be nice to use it together with the new Success Symbol which has been introduced in 11.3.

$\endgroup$

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.