next up previous index
Next: Interrupts Up: Events and Interrupts Previous: Events   Index

Subsections


Errors

Errors handling is one particular use of events. The main property of error events is that they have a culprit goal, ie. the goal that detected or caused the error. The error handler obtains that goal as an argument.

The errors that the system raises have numerical identifiers, as documented in appendix D. Whenever an error occurs, the ECLiPSe system identifies the type of error, and calls the appropriate handler. For each type of error, it is possible for the user to define a separate handler. This definition will replace the default error handling routine for that particular error - all other errors will still be handled by their respective handlers. It is of course possible to associate the same user defined error handler to more than one error type.

When a goal is called and produces an error, execution of the goal is aborted and the appropriate error handler is invoked. This invocation of the error handler is seen as replacing the invocation of the erroneous goal:

For errors that are classified as warnings the second point is somewhat different: If the handler succeeds, the goal that raised the warning is allowed to continue execution.

Apart from binding variables in the erroneous goal, error handlers can also leave backtrack points. However, if the error was raised by an external or a builtin that is implemented as an external, these choicepoints are discarded14.1.

Error Handlers

The predicate set_error_handler/2 is used to assign a procedure as an error handler. The call
set_error_handler(N, PredSpec)
sets the error handler for error type N to the procedure specified by PredSpec, which must be of the form Name/Arity.

The corresponding predicate get_error_handler/3 may be used to identify the current handler for a particular error. The call

get_error_handler(N, PredSpec, HomeModule)
will, provided N is a valid error identifier, unify PredSpec with the specification of the current handler for error N in the form Name/Arity, and HomeModule will be unified with the module where the error handler has been defined. Note that this error handler might not be visible from every module and therefore may not be callable.

To re-install the system's error handler in case the user error handler is no longer needed, reset_error_handler/1 should be used. reset_error_handlers/0 resets all error handlers to their default values.

To enable the user to conveniently write predicates with error checking the built-ins

error(N, Goal)
error(N, Goal, Module)
are provided to raise the corresponding error number N with the culprit Goal. Inside tool procedures it is usually necessary to use error/3 in order to pass the caller module to the error handler. Typical error checking code looks like this
increment(X, X1) :-
        integer(X) ->
            X1 is X + 1
        ;
            error(5, increment(X, X1)).

The predicate current_error/1 can be used to yield all valid errors, a valid error is that one to which an error message and an error handler are associated. The predicate error_id/2 gives the corresponding error message to the specified error number. To ease the search for the appropriate error number, the library util contains the predicate

list_error(Text, N, Message)
which returns on backtracking all the errors whose error message contains the string Text.

The ability to define any Prolog predicate as the error handler permits a great deal of flexibility in error handling. However, this flexibility should be used with caution. The action of an error handler could have side effects altering the correctness of a program; indeed it could be responsible for further errors being introduced. One particular area of danger is in the use of input and output streams by error handlers. For example: a particular error handler may interact with the user at the terminal, to explain the nature of the error and ask for directions regarding what action should be taken. Care should be taken in such a case to ensure that the error handler does not affect the input to the program. If it does, since program execution continues normally after exit of the error handler, any input consumed by the error handler is lost.

Arguments of Error Handlers

An error handler has 3 optional arguments. The first argument is the number that identifies the error, the second argument is the culprit (a structure corresponding to the call which caused the error). For instance, if, say, a type error occurs upon calling the second goal of the procedure p(2, Z):
 p(X, Y) :- a(X), b(X, Y), c(Y).
the structure given to the error handler is b(2, Y). Note that the handler could bind Y which would have the same effect as if b/2 had done the binding.

The third argument is only defined for a subset of the existing errors. If the error occurred inside a tool body, it holds the caller module, otherwise it is a free variable. Note that some events are not errors but are used for different purposes. In thoses cases the second and third argument are sometimes used differently. See Appendix D for details.

The error handler is free to ignore some of these arguments, i.e. it can have any arity from 0 to 3. The first argument is provided for the case that the same procedure serves as the handler for several error types - then it can distinguish which is the actual error type. An error handler is just an ordinary Prolog procedure and thus within it a call may be made to any other procedure, or any built in predicate; this in particular means that a call to exit_block/1 may be made (see the section on the block/3 predicate). This will work 'through' the call to the error handler, and so an exit may be made from within the handler out of the current block (i.e. back to the corresponding call of the block/3 predicate). Specifying the predicates true/0 or fail/0 as error handlers will make the erroneous predicate succeed (without binding any further variables) or fail respectively.


User Defined Errors

The following example illustrates the use of a user-defined error. We declare a handler for the event 'Invalid command' and raise the new error in the application code.
% Command error handler - output invalid command, sound bell and abort
command_error_handler(_, Command) :-
        printf("\007\nInvalid command: %w\n", [Command]),
abort.

% Activate the handler
:- set_event_handler('Invalid command', command_error_handler/2).

% top command processing loop
go :-
        writeln("Enter command."),
        read(Command),
        ( valid_command(Command)->
            process_command(Command),
            go
        ;
            error('Invalid command',Command) % Call the error handler
).

% Some valid commands
valid_command(start).
valid_command(stop).


next up previous index
Next: Interrupts Up: Events and Interrupts Previous: Events   Index

1999-08-06