# Best practice for catch/3 with multiple possible errors?

**URL:** <https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555>\
**Category:** Predicate\
**Tags:** how-to\
**Created:** [October 13, 2021, 9:59pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555 "2021-10-13T21:59:13Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 13, 2021, 9:59pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/1 "2021-10-13T21:59:13Z")

</div>

I have a situation where there are multiple possible errors – I want to catch them and convert the result to failure, but allow any other errors to propagate. This is the code I’ve written … is there a better way of doing this? (Context: I’m doing a bit of cleanup to library(rbtrees))

```prolog
is_rbtree(t(_,T)) :-
    catch(rbtree1(T), Err, true),
    ( var(Err)
    -> true
    ; Err = msg(_,_)
    -> fail
    ; Err = error(instantiation_error,_)
    -> fail
    ; Err = error(existence_error(matching_rule,_),_)
    -> fail
    ; throw(Err)
    ).

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 14, 2021, 5:37am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/2 "2021-10-14T05:37:09Z")

</div>

Here’s another way of doing the same thing:

```prolog
is_rbtree(t(_,T)) =>
    catch(
          catch(
                catch(rbtree1(T),
                      msg(_,_),
                      fail),
                error(instantiation_error,_),
                fail),
          error(existence_error(matching_rule,_),_),
          fail).

```

This is shorter and avoids a call to var/1; but it’s also a bit less efficient (which may or may not matter) and it’s not very readable.

---

<div class="post-metadata">

**Author:** ![grossdan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/grossdan/32/23_2.png) [@grossdan](https://swi-prolog.discourse.group/u/grossdan)\
**Post date:** [October 14, 2021, 6:38am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/3 "2021-10-14T06:38:42Z")

</div>

I keep wondering how to best deal with errors – what approach works best in general, architecturally speaking, and for Prolog in particular.

Essentially, converting to failure shields the caller from the type of error but also might have “failure” more ambiguous.

It would be great if we could a discussion about that …

Edit:

I read up one time on an approach developed by a German software house SD&M, which they called QUASAR. They basically advocate for a facade approach – where facade “security” components take care of all failure while internal components are freed from the burden to deal with failure.

Security Facade components either succeed or fail completely – internally, they can retry and do other smart things.

I guess this approach is mostly used in enterprise settings.

I guess this be “overkill” for a low level component such as rb\_trees

Dan

---

<div class="post-metadata">

**Author:** ![oskardrums](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/oskardrums/32/3594_2.png) [@oskardrums](https://swi-prolog.discourse.group/u/oskardrums)\
**Post date:** [October 14, 2021, 6:57am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/4 "2021-10-14T06:57:07Z")

</div>

How about a helper predicate?  
like:

```prolog
is_rbtree(t(_,T)) :-
    catch(rbtree1(T), Err, is_rbtree_error(Err)).

is_rbtree_error(msg(_, _)) :- fail. % EDIT: missing !/0, see note below
...
is_rbtree_error(Err) :- throw(Err).

```

EDIT: in case the body of the “handler” clause is not deterministic (which fail/0 clearly isn’t) we must add the cut:

```prolog
is_rbtree_error(msg(_, _)) :- !, fail.
is_rbtree_error(foo) :- bar.
is_rbtree_error(Err) :- throw(Err).

:- det(bar).
bar.

```

It may be a good choice to add the cut to deterministic clauses as well to avoid spurious choice points.  
One can also use SSU as an alternative for the explicit !/0:

```prolog
is_rbtree_error(msg(_, _)) => fail.
...
is_rbtree_error(Err) => throw(Err).

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 14, 2021, 6:57am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/5 "2021-10-14T06:57:11Z")

</div>

> [@grossdan](#):
>
> Essentially, converting to failure shields the caller from the type of error but also might have “failure” more ambiguous.

In this particular case, the predicate is\_rbtree/1 wraps another predicate that can either fail or throw an exception. So, here it’s reasonable to convert an exception to failure.

But my question was about the best way to catch multiple different errors – how they are handled is not my question.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 14, 2021, 7:11am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/6 "2021-10-14T07:11:53Z")

</div>

> [@oskardrums](#):
>
> How about a helper predicate?

Nice! Thank-you.

---

<div class="post-metadata">

**Author:** ![grossdan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/grossdan/32/23_2.png) [@grossdan](https://swi-prolog.discourse.group/u/grossdan)\
**Post date:** [October 14, 2021, 7:26am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/7 "2021-10-14T07:26:02Z")

</div>

Thanks.

Indeed, i used the question to ask a broader question, although its related – the architecture of failure handing may also suggest the approach – such as whether further hands-offs are made.

Dan

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 14, 2021, 8:48am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/8 "2021-10-14T08:48:02Z")

</div>

I see two issues. One is selecting exceptions you want to handle. If there is a good pattern where unification does the trick, this is fairly ok. If not, you need a more general pattern and you catch too many, so you need to filter on the ones you want to handle and re-throw otherwise. This is all a bit clumsy and it is also bad for debugging as if the original exception is due to a bug it will now be reported as to be causes by the re-throw ☹

I’ve considered evaluating constraints when unifying the exception ball. That would allow us to be selective by defining a predicate that produces a pattern that unifies only with the exceptions we really want to process. It is a complicated and expensive though ☹ Possibly we need a catch/2, so we can write something like below. The semantics would be that if no clause matches we consider the exception not caught. It would solve some problems. Probably needs more thought though.

```prolog
     catch(Goal, on_error).

on_error(Pattern1) => handle_1.
on_error(Pattern2) => handle_2.

```

As is, exceptions are rather slow as well. If I recall well, SWI-Prolog was according to some old report from Bart Demoen doing quite well compared to many other Prolog implementations, but it remains slow. I do think there is room for improvement, notably for the no-error case.

All in all, I think one should try to avoid relying on processing exceptions for “normal” things. This smells like wrong design were we try to turn something designed to throw exceptions into a normal true/false Prolog predicate. One should try to opt for the reverse: have the low-level checking predicates succeed/fail and use those to throw an error when we detect invalid use of some predicate.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [October 14, 2021, 9:00am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/9 "2021-10-14T09:00:58Z")

</div>

> [@jan](#):
>
> exception ball.

It sort of makes sense but could `ball` be a typo?

* * *

**EDIT**

After seeing [reply](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/10) by Jan W. and being attentive to the idea of a ball is thrown, discovered the terminology is noted in the ISO Prolog standard:

> **7.8.9**
> 
> The catch and throw (7.8.10) control constructs enable execution to continue after an error without intervention from the user.
> 
> catah(Goa1, Catcher, Recovery) is similar to call(Goal), however when throw(Ball) is called, the current flow of control is interrupted, and control returns to a call of catch/3 that is being executed.

> NOTES
> 
> 1 The names of the arguments have been chosen because throw/1 behaves as though it is throwing a ball to be caught by an active call of catch/3.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 14, 2021, 9:13am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/10 "2021-10-14T09:13:13Z")

</div>

The thing you throw is often called the _ball_ 🙂

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [October 14, 2021, 9:58am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/11 "2021-10-14T09:58:59Z")

</div>

In searching for related code examples in trusted repositories found the following code.  
These are noted not to suggest it as an answer but as reference material if needed.

> **Click triangle to expand**
>
> [packages-clib/filesex.pl at 50e6a8a526e467171fffedad0d8bcd921bda0c4c · SWI-Prolog/packages-clib · GitHub](https://github.com/SWI-Prolog/packages-clib/blob/50e6a8a526e467171fffedad0d8bcd921bda0c4c/filesex.pl#L333-L361)
> 
> [packages-http/thread\_httpd.pl at 1da608a12443b5610998c663073956b98ea2b8da · SWI-Prolog/packages-http · GitHub](https://github.com/SWI-Prolog/packages-http/blob/1da608a12443b5610998c663073956b98ea2b8da/thread_httpd.pl#L437-L451)
> 
> [packages-pldoc/doc\_html.pl at ce3513a9385f00a4193e6388d28d6dc85eb3119e · SWI-Prolog/packages-pldoc · GitHub](https://github.com/SWI-Prolog/packages-pldoc/blob/ce3513a9385f00a4193e6388d28d6dc85eb3119e/doc_html.pl#L511-L534)
> 
> [packages-xpce/prolog\_mode.pl at 60e3d809ccc94b7366b1b3bae8b8e5d83a21d0c8 · SWI-Prolog/packages-xpce · GitHub](https://github.com/SWI-Prolog/packages-xpce/blob/60e3d809ccc94b7366b1b3bae8b8e5d83a21d0c8/prolog/lib/emacs/prolog_mode.pl#L960-L989)
> 
> This is interesting because assert is done before failing.
> 
> [packages-xpce/isocomp.pl at 549bab1a2335e30af21e188c25e94d60b08fd880 · SWI-Prolog/packages-xpce · GitHub](https://github.com/SWI-Prolog/packages-xpce/blob/549bab1a2335e30af21e188c25e94d60b08fd880/prolog/lib/isocomp.pl#L193-L219)
> 
> [packages-xpce/status.pl at d5bfde3b644177a43b295f9d84425167ce23acac · SWI-Prolog/packages-xpce · GitHub](https://github.com/SWI-Prolog/packages-xpce/blob/d5bfde3b644177a43b295f9d84425167ce23acac/prolog/lib/trace/status.pl#L308-L362)
> 
> [swipl-devel/aggregate.pl at 96f65b30253bac200c0b903bb396d2f0a22bcf28 · SWI-Prolog/swipl-devel · GitHub](https://github.com/SWI-Prolog/swipl-devel/blob/96f65b30253bac200c0b903bb396d2f0a22bcf28/library/aggregate.pl#L158-L256)
> 
> This is interesting because it has a mode to determine what to do.  
> [swipl-devel/prolog\_source.pl at 6dfc14f0f8f741a5bab10cb129aa1c2f2ed20682 · SWI-Prolog/swipl-devel · GitHub](https://github.com/SWI-Prolog/swipl-devel/blob/6dfc14f0f8f741a5bab10cb129aa1c2f2ed20682/library/prolog_source.pl#L536-L564)
> 
> An example of throw inside of a catch.  
> [packages-clib/filesex.pl at 50e6a8a526e467171fffedad0d8bcd921bda0c4c · SWI-Prolog/packages-clib · GitHub](https://github.com/SWI-Prolog/packages-clib/blob/50e6a8a526e467171fffedad0d8bcd921bda0c4c/filesex.pl#L420-L438)

---

<div class="post-metadata">

**Author:** ![grossdan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/grossdan/32/23_2.png) [@grossdan](https://swi-prolog.discourse.group/u/grossdan)\
**Post date:** [October 14, 2021, 10:30am UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/12 "2021-10-14T10:30:47Z")

</div>

Hi Jan,

Suppose you do want to “rewind” some processing to an earlier state and pass some data across – wouldn’t the semantics of catch/throw not be a good match – even though it is intended to handle exceptions.

The point is that the cost of unwinding the stack via failure and “back passing” a value via an argument might be much larger than having it done via the throw mechanism.

How else would you recommend doing some a control flow.

Dan

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [October 14, 2021, 12:17pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/13 "2021-10-14T12:17:55Z")

</div>

Please don’t take this as anything other than just trying to shine some light on what you seek, which is to cleanup library(rbtrees).

Instead of focusing on the catch/throw part of the question, in looking at it from what is the predicate is\_rebtree/1 suppose to do one has to ask, is is\_rbtreee/1 a predicate that should return only success or failure?

When I see predicates starting with the word `is` I don’t expect side effects, no exceptions, no messages, no binding of values, just success or failure of the predicate.

Digging deeper into how I reason about such is that is\_rbtree/1 looks to be a recognizer (think parser that returns either success or failure) and is a wrapper around a parser that suppresses all error messages. In looking at the current code for is\_rbtree/1, that is what I am seeing

```prolog
is_rbtree(X) :-
    var(X), !, fail.
is_rbtree(t(Nil,Nil)) :- !.
is_rbtree(t(_,T)) :-
    catch(rbtree1(T), msg(_,_), fail).

```

with `rbtree1/1` being the parser that throws.

If a predicate is needed to check if a value is an rb\_tree and return the errors then I would expect a parser predicate with 2 arguments, the first augment being the value to be parsed and the second being an option list with an option for what to do with the parsing errors (collect them into a list, print them as found, …). I am not finding an exported predicate for such with SWI-Prolog Red-Black trees. `rbtree1/1` would be a good start.

If the data is external data being loaded then I would look to rdf\_load/2 for inspiration. However rb\_trees tend to be internal so I would look to json\_read/2 or similar for inspiration.

When I was searching trusted SWI-Prolog repositories for code that would catch an error and massage specific errors into fail or re-export the error, it was like looking for a needle in a hay stack. Nothing I found exactly matched all three.

HTH

* * *

My current list of trusted SWI-Prolog repositories that I search. More are [trusted](https://swi-prolog.discourse.group/t/useful-prolog-references/1089#github-24) but not in the list as it takes about a minute to search these and I do tens of searches a day.

> **Click triangle to expand**
>
> bench-master  
> contrib-protobufs-master  
> docker-swipl-linux-ci-master  
> packages-bdb-master  
> packages-chr-master  
> packages-clib-master  
> packages-cppproxy-master  
> packages-http-master  
> packages-inclpr-master  
> packages-jpl-master  
> packages-ltx2htm-master  
> packages-odbc-master  
> packages-pcre-master  
> packages-pengines-master  
> packages-pldoc-master  
> packages-RDF-master  
> packages-real-master  
> packages-semweb-master  
> packages-sgml-master  
> packages-ssl-master  
> packages-utf8proc-master  
> packages-xpce-master  
> packages-yaml-master  
> packages-zlib-master  
> pengines-master  
> plweb-blog-master  
> plweb-examples-master  
> plweb-master  
> plweb-www-master  
> rclswi-master  
> swipl-devel-master  
> swipl-master  
> swipl-server-js-client-master  
> swish-master  
> webstat-master

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 14, 2021, 5:34pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/14 "2021-10-14T17:34:21Z")

</div>

> [@jan](#):
>
> Possibly we need a catch/2

One alternative would be to allow a list in catch/3. If something throws a list (I think this is unlikely), it can always be wrapped in a single-item list.

Using this, my code would be:

```prolog
is_rbtree(t(_,T)) :-
    catch(rbtree1(T), 
          [msg(_,_),
           error(instantiation_error,_),
           error(existence_error(matching_rule,_),_)],
          fail).

```

However, a more general catch/2 would probably still be a good thing, although I don’t know how much it would be used (and @ridgeworks would probably think it’s bad to encourage use of exceptions by making them easier to use). As @jan pointed out, using exceptions for “normal” things smells like wrong design, although it’s an interesting design question whether an “is\__type_” predicate should fail or throw an exception (in the case of library(rbtrees), there’s a private predicate that throws an exception with more information, which is wrapped in a predicate that simply succeeds or fails).

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 14, 2021, 5:36pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/15 "2021-10-14T17:36:38Z")

</div>

> [@jan](#):
>
> I think one should try to avoid relying on processing exceptions for “normal” things. This smells like wrong design were we try to turn something designed to throw exceptions into a normal true/false Prolog predicate

However, an exception can give more information about a failure, which can be very useful for debugging.

On a related issue, I was thinking about @ridgeworks’s [Errors considered harmful](https://swi-prolog.discourse.group/t/errors-considered-harmful/3574), in particular how the “=\>” ([single-sided unification](https://www.swi-prolog.org/pldoc/man?section=ssu)) works (which throws an `exitence_error(matching_rule,_)` exception). In the particular code I was working on, a wrong answer is produced if a parameter that’s expected to be sufficiently ground is uninstantiated – so, the correct behavior is to either fail (by an explicit `nonvar(Tree)`) or to throw an exception. Single-sided unification provides a painless way of ensuring that an uninstantiated variable isn’t passed to the predicate.

A missing item from Prolog’s notion of exceptions is an exception hierarchy, something that both Java and Python have (as well as ways of handling multiple exceptions, combined with a `finally` that works a lot like setup\_call\_cleanup/3). The exception hierarchy (such as [Python’s](https://docs.python.org/3/library/exceptions.html#exception-hierarchy)) can be somewhat simulated in Prolog by clever syntax in terms, I suppose …

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 14, 2021, 5:39pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/16 "2021-10-14T17:39:56Z")

</div>

> [@EricGT](#):
>
> If a predicate is needed to check if a value is an rb\_tree and return the errors then I would expect a parser predicate with 2 arguments, the first augment being the value to be parsed and the second being an option list with an option for what to do with the parsing errors (collect them into a list, print them as found, …).

This is a nice idea, but it’s probably quite a bit more work. In the parser world, it’s well recognized that good error handling is difficult. The nice thing about exceptions is that they allow you to just stop the computation with an exact description of what went wrong (“exact” is a bit of an exaggeration – as anyone who’s modified a simple parser to report source code position for errors will attest).

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [October 15, 2021, 2:25pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/18 "2021-10-15T14:25:45Z")

</div>

> [@peter.ludemann](#):
>
> However, a more general catch/2 would probably still be a good thing, although I don’t know how much it would be used (and @ridgeworks would probably think it’s bad to encourage use of exceptions by making them easier to use).

Although they share a common mechanism, I view errors and exceptions to be quite different semantically. Exceptions are a perfectly valid control structure (i.e., deep exits) and anything that makes them easier to use is a good thing.

And there are perfectly valid reasons to generate errors when there is no reasonable chance of continuing, e.g., run out of memory (or some other resource). But I think there is currently a whole class of errors (type errors, domain errors, etc.) that would be better served by failure for the reasons I tried to explain in the previous thread (and this particularly applies to built-in primitives).

> [@jan](#):
>
> One should try to opt for the reverse: have the low-level checking predicates succeed/fail and use those to throw an error when we detect invalid use of some predicate.

Totally agree, although I would extend this philosophy beyond just “checking” predicates. Exceptions should be used sparingly (IMO).

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [October 17, 2021, 1:09pm UTC](https://swi-prolog.discourse.group/t/best-practice-for-catch-3-with-multiple-possible-errors/4555/19 "2021-10-17T13:09:11Z")

</div>

For those wanting to see the update:

> <https://github.com/SWI-Prolog/swipl-devel/commit/0ad98034f88b1a316db637a599668d8a174aecca>
