# Best practices for throw(...)?

**URL:** https://swi-prolog.discourse.group/t/best-practices-for-throw/2973
**Category:** Predicate
**Created:** [September 26, 2020, 12:45am UTC](https://swi-prolog.discourse.group/t/best-practices-for-throw/2973 "2020-09-26T00:45:43Z")
**Posts on this page:** 4
**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: [September 26, 2020, 12:45am UTC](https://swi-prolog.discourse.group/t/best-practices-for-throw/2973/1 "2020-09-26T00:45:43Z")

</div>

I’ve read and reread the [documentation for the exception term](https://www.swi-prolog.org/pldoc/man?section=exceptterm) for throw/1, and I’m still confused.

For one thing, in `error(..., context(Location,Message)`, the backtrace doesn’t seem to fill in `Location`:

```prolog
?- listing(type_check:control_type_error).
control_type_error(Error, Goal, Context) :-
    throw(error(Error, context(Goal, Context))).

?- type_check:control_type_error(failure, 1=2, qqsv).
ERROR: Unknown error term: failure (qqsv)
ERROR: In:
ERROR: [11] throw(error(failure,context(...,qqsv)))
ERROR: [9] toplevel_call(user:type_check: ...) at /usr/lib/swi-prolog/boot/toplevel.pl:1113
ERROR: 
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.

```

If I want to define a predicate that throws an exception on failure, is this the best way?

```prolog
must_once(Goal) :-
    ( call(Goal)
    -> true
    ; throw(error(must_once_failed, context(_,goal:Goal)))
    ).

```

Or is this better?

```prolog
must_once_msg(Goal, Msg, MsgArgs) :-
    ( call(Goal)
    -> true
    ; functor(Goal, Pred, Arity),
        format(string(MsgStr), Msg, MsgArgs),
        throw(error(must_once_failed(Goal),
                    context(Pred/Arity, MsgStr)))
    ).

```

Or something else?

---

<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: [September 26, 2020, 7:31am UTC](https://swi-prolog.discourse.group/t/best-practices-for-throw/2973/3 "2020-09-26T07:31:20Z")

</div>

> [@peter.ludemann](#):
>
> the backtrace doesn’t seem to fill in `Location` :

Well, the _Location_ is the stack. As it says, the interesting frame is missing due to last call optimization. Handing your own name/arity will tell you the predicate, but not the stack. IMO that is a lot more typing, making your code a lot bulkier and harder to read while a partial stack is often still more useful than just a predicate without any context.

Last call optimization is necessary, but has its disadvantages when it comes to debugging. Prolog’s backtracking _time machine_ is a HUGE advantage over other languages though 🙂

---

<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: [September 26, 2020, 3:46pm UTC](https://swi-prolog.discourse.group/t/best-practices-for-throw/2973/4 "2020-09-26T15:46:44Z")

</div>

So, is something like this the preferred form? (which is also what `type:check_control_type_error/3` uses):

```prolog
throw(error(must_once_failed, context(_,goal:Goal)))

```

---

<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: [September 26, 2020, 4:15pm UTC](https://swi-prolog.discourse.group/t/best-practices-for-throw/2973/5 "2020-09-26T16:15:00Z")

</div>

I’d go for

```
error(must_once_failed(Goal), _).

```

I.d., leave the second argument simply unbound. Especially for your own errors you can capture enough context to generate a sensible message. Note that SWI-Prolog handles exceptions of the shape `error(Formal, ImplDependent)` special in the sense that the debugger wants to do something sensible with them. Other exception terms are left alone by the debugger and should be used for scenarios where you throw and intend to capture the exception as a normal part of the execution.

ISO had to split into Formal and ImplDependent as one system may be able to provide more context than another. So, ISO is limited in what it can demand to go into the Formal part of an error. If you define your own error you do not have that limitation.

If you want to stay in the ISO style, the formal part is \*\_error(Arg, …). A possible choice could be determinism\_error(Expected, Found, Goal), e.g.

```
determinism_error(det, fail, Goal).

```

That said, IMHO far too much brain power of the Prolog community was wasted on this stuff ☹ . For SWI-Prolog though, dealing with the error/2 vs other exceptions and typically leaving the second argument unbound ensures your code cooperates best with the development environment.
