Home Contents Index Summary Previous Next

3.8 ISO compliant Exception handling

SWI-Prolog defines the predicates catch/3 and throw/1 for ISO compliant raising and catching of exceptions. In the current implementation (2.9.0), only part of the built-in predicates generate exceptions. In general, exceptions are implemented for I/O and arithmetic.

catch(:Goal, +Catcher, :Recover)
Behaves as call/1 if no exception is raised when executing Goal. If a exception is raised using throw/1 while Goal executes, and the Goal is the innermost goal for which Catcher unifies with the argument of throw/1, all choicepoints generated by Goal are cut, and Recover is called as in call/1.

The overhead of calling a goal through catch/3 is very comparable to call/1. Recovery from an exception has a similar overhead.

throw(+Exception)
Raise an exception. The system will look for the innermost catch/3 ancestor for which Exception unifies with the Catcher argument of the catch/3 call. See catch/3 for details.

If there is no catch/3 willing to catch the error in the current Prolog context, the toplevel (prolog/0) catches the error and prints a warning message. If an exception was raised in a callback from C (see chapter 5), PL_next_solution() will fail and the exception context can be retrieved using PL_exception().

3.8.1 Debugging and exceptions

Before the introduction of exceptions in SWI-Prolog a runtime error was handled by printing an error message, after which the predicate failed. If the feature (see feature/2) debug_on_error was in effect (default), the tracer was switched on. The combination of the error message and trace information is generally sufficient to locate the error.

With exception handling, things are different. A programmer may wish to trap an exception using catch/3 to avoid it reaching the user. If the exception is not handled by user-code, the interactive toplevel will trap it to prevent termination.

If we do not take special precautions, the context information associated with an unexpected exception (i.e. a programming error) is lost. Therefore, if an exception is raised, which is not caught using catch/3 and the toplevel is running, the error will be printed, and the system will enter trace mode.

If the system is in an non-interactive callback from foreign code and there is no catch/3 active in the current context, it cannot determine whether or not the exception will be caught by the external routine calling Prolog. It will then base its behaviour on the feature debug_on_error:

While looking for the context in which an exception takes place, it is adviced to switch on debug mode using the predicate debug/0.

3.8.2 The exception term

Builtin predicates generates exceptions using a term error(Formal, Context). The first argument is the `formal' description of the error, specifying the class and generic defined context information. When applicable, the ISO error-term definition is used. The second part describes some additional context to help the programmer while debugging. In its most generic form this is a term of the form context(Name/Arity, Message), where Name/Arity describes the built-in predicate that raised the error, and Message provides an additional description of the error. Any part of this structure may be a variable if no information was present.

3.8.3 Printing a message from an exception

The predicate print_message/2 may be used to print an exception term in a human readable format:

print_message(+Kind, +Term)
This predicate is modelled after the Quintus predicate with the same name, though its current implementation is incomplete. It is used only for printing messages from exceptions from built-in predicates. Kind is one of informational, warning, consterror, help or silent. Currently only error is defined. Term is an error(2) term described in section 3.8.2. A human-readable message is printed to the stream user_error.

This predicate first obtains the `human translation' of Term and then calls message_hook/3. If this fails the message is printed to the stream user_error.

The print_message/2 predicate and its rules are in the file <plhome>/boot/messages.pl, which may be inspected for more information on the error messages and related error terms.

message_hook(+Term, +Kind, +Message)
Hook predicate that may be define in the module user to intercept messages from print_message/2. Term and Kind are the same as passed to print_message/2. Message is a string containing the human readable translation of the message. If this predicate succeeds, print_message/2 considers the message printed.

This predicate should be defined dynamic and multifile to allow other modules defining clauses for it too.