Programming in XPCE/Prolog: Section 10.8

## 10.8 Errors

Errors are abnormalities that are detected during a programs execution. Errors may be caused by bugs in XPCE, bugs in the application program and finally by the application user making errors in operating the application (e.g. specifying a protected file).

Errors may also be discriminated according to their `seriousness': If a certain font cannot be found it can easily be substituted by another. If a method expects an integer argument but the actual argument is a graphical object it is impossible to carry-out the operation. In such cases XPCE will normally trap the tracer. If the user decides to continue execution the method will return failure to its caller. Finally, some problems are categorised as `fatal'. When such a problem is encountered XPCE does not know how execution can be continued.

All errors (except for some that may result from XPCE bugs during the boot phase of XPCE) are represented by an error object. An error object has the following properties:

- id
  Unique identifier name of the error. It may be used to generate errors; look-up error objects in the @errors database or catch errors (see pce_catch_error/2).
- kind
  The kind describes how serious the error is considered to be. The possible values are: ignored if the error is (currently) not regarded an error at all; warning if the error is to be reported, but no further action is required; error if the error is to be fixed. After printing the error the system will start the tracer, allowing a programmer to examine the problem context. Finally, fatal errors do not allow execution to be continued. The system will print context information and request Prolog to abort back to the Prolog interactive top level.
- feedback
  Determines how the error is to be reported. If `print` the error is printed in the Prolog window. If `report` the error is reported using the report mechanism described in section 10.7. The `report' mechanism is for errors that may be caused by application users, for example file errors. If `throw` and there is a Prolog goal on the stack, the error is mapped to a Prolog exception. See below.

  In the runtime-system, all errors use feedback `report'.

- format
  A format specification to construct a message text from the context arguments provided by the generator of the error.

The online manual ``Errors Browser'' may be used to examine the defined errors; change attributes of errors and get precise description of errors.

### 10.8.1 Handling errors in the application

Sometimes the application wants to anticipate on certain errors. Explicit testing of all conditions is a cumbersome solution to this problem. Therefore XPCE allows catching of errors by the application.

There are two mechanism available to do this. Regardless of the `error`<-`feedback' type of the error, all except fatal errors can be silenced using pce_catch_error/2:

pce_catch_error(+ErrorSpec, :Goal)
  Run Goal like once/1. It an error matching ErrorSpec is raised, this error is not reported, but stored in `@pce`<-`last_error'. ErrorSpec is the `<-`id of an error, a chain holding error-ids or @default. The latter implies none but fatal errors are reported.

  The example below silently ignores errors from creating a backup of File. Note that the call does fail if backup raises an error.

              ...,
              pce_catch_error(backup_file, send(File, backup)),
              ...

If the `<-`feedback of the error is `throw` and the error is not silenced with pce_catch_error/2 it is mapped to a Prolog exception of the form

> `error(`pce(Id, ContextArgs)`, Goal)`

For example:

    ?- catch(send(@pce, foobar), E, true).

    E = error(pce(no_behaviour, [@pce/pce,  (->), foobar]),
              send(@pce/pce, foobar))

### 10.8.2 Raising errors

The application programmer may define new (application specific) errors. The error object is a normal XPCE object and may thus be created using new/2. An error is raised by invoking `object`->`error'. The example below illustrates this:

    :- new(_, error(no_user,
                    '%N: Unknown user: %s',
                    warning, report)).

            ...,
            (   get(UserDatabase, user, Name)
            ->  ...
            ;   send(UserDatabase, error, no_user, Name)
            ),
            ...

Note that the names of errors should be unique. It is advised to reuse existing error-id's if possible.

### 10.8.3 Repairable errors

On trapping certain `repairable` errors, XPCE will first raise an exception. Exceptions may be trapped by an exception handler which may solve the problem. If the exception-handler fails to solve the problem, XPCE will raise an error. See section 10.8.

Exceptions are raised by invoking `@pce`->`exception: id, arg ...'. Exception handlers are registered in the sheet `@pce`->`exception_handlers', which maps an exception-id onto a code object that handles the exception. The following illustrates this:

    1 ?- [user].
    |: add_user(Name) :- write(Name), nl.
    ^D

    2 ?- send(@pce?exception_handlers, value,
              no_user,
              message(@prolog, add_user, @arg1)).

    3 ?- send(@pce, exception, no_user, fred).
    fred

The context arguments passed with an exception are defined by the code raising the exception. The currently defined exceptions are listed below. See also the online manual: `pce`->`exception' and `pce`<-`exception_handlers'.

- undefined_class
  An attempt is made to reference a non-existing class while doing one of the following: create an object; load an object from file using `File`<-`object'; create a subclass. @arg1 is bound to the class-name. This trap is used by pce_autoload/2, as well as by the code that realises compiled classes.
- undefined_assoc
  An attempt is made to resolve a symbolic reference (i.e. @pce), but the reference is unknown. @arg1 is bound to the missing reference name. This trap is used by pce_global/2.
- redefined_assoc
  An attempt is made to create an object with the same symbolic reference as an already existing object. @arg1 is bound to the already existing reference name. This trap is used by `library(pce_renew)`.
- initialisation_failed
  The `->`initialisation method for some instance failed. @arg1 is bound to the (partial) instance; @arg2, ... are bound to the arguments given to the new-operation.