ISO demands that throw/1 make a copy of Exception, walk up the stack to a catch/3 call, backtrack and try to unify the copy of Exception with Catcher. SWI-Prolog delays backtracking until it actually finds a matching catch/3 goal. The advantage is that we can start the debugger at the first possible location while preserving the entire exception context if there is no matching catch/3 goal. This approach can lead to different behaviour if Goal and Catcher of catch/3 call shared variables. We assume this to be highly unlikely and could not think of a scenario where this is useful.80I'd like to acknowledge Bart Demoen for his clarifications on these matters.
In addition to explicit calls to throw/1, many built-in predicates throw exceptions directly from C. If the Exception term cannot be copied due to lack of stack space, the following actions are tried in order:
- If the exception is of the form
error(Formal, ImplementationDefined)
, try to raise the exception without the ImplementationDefined part. - Try to raise
error(
.resource_error(stack)
, global) - Abort (see abort/0).
If an exception is raised in a call-back from C (see chapter 12) and not caught in the same call-back, PL_next_solution() fails and the exception context can be retrieved using PL_exception().