Class-Based Exceptions

(see also, the application help)

In class-based exception-handling, different sorts of exceptions are represented by exception classes; at runtime, the corresponding exceptions are represented by object instances of these classes. Consequently, exception objects can be used to transport additional information about the exception in the form of attributes. These can give the handler information about the context in which the exception occurred.

Exception classes are derived from the specific class CX_ROOT and have the prefix CX_. They are usually global, although you can create local exception classes if you want.

In principle, exception classes are normal classes with one limitation: apart from the constructor, no methods can be defined for them. However, CX_ROOT has some pre-defined methods available, which can then be inherited by all exception classes:

GET_TEXT: Returns a text description of the exception

GET_SOURCE_POSITION: Returns the point at which the exception occurred

The following attributes have also been defined in CX_ROOT:

TEXTID: Used to define different texts for exceptions of a particular exception class. Affects the result of the method GET_TEXT. For more details on assigning texts to exceptions, see Exception Texts.

PREVIOUS: If one exception is mapped to another, this attribute stores the original exception, which allows the system to build a chain of exceptions.

KERNEL_ERRID: Contains the name of the appropriate runtime error if the exception was triggered from the kernel. If the exception was raised using a RAISE EXCEPTION, this attribute is initial.

Exceptions are a fundamental part of the interface of a procedure. For this reason, all exceptions that may occur when a procedure is called must be declared in the procedure ( FORM, FUNCTION, METHOD) definition. You declare the exception adding a RAISING clause to the procedure definition.

The compiler checks to see whether or not all the exceptions that could occur in a procedure, but are not caught locally, are declared in the interface. If exceptions that could be raised are not declared in the interface, the system generates a TODO warning (a syntax error in such a situation would make changing the interface much more difficult). At runtime, if an exception leaves the call interface of a procedure without having been declared in a RAISING clause for that procedure, a runtime error occurs. This combination of static and dynamic checks guarantees that the using procedure only needs to deal with the exceptions that have been declared in its interface.

In some cases, however, rigidly applying the rules for declaring exceptions would be counter-productive - there are errors that can occur in many different places, but are not usually handled explicitly (like resource bottlenecks). For consistency, you would have to declare these errors in almost every interface. There are also errors that you can rule out - such as conditions applied to the actual parameters of a procedure call interface, where these actual parameters can be tested before the procedure is called, or if the calling procedure already knows that these conditions have been fulfilled.

To take such exceptions into account, exceptions are assigned to various categories, which have different rules on the declarations that must be made and on the consequences of not complying with these rules. Exceptions are assigned to different sub-trees in the exception class hierarchy. The top two levels in this hierarchy look like this:


CX_SY_ROOT
  |
  |--CX_STATIC_CHECK
  |
  |--CX_DYNAMIC_CHECK
  |
  |--CX_NO_CHECK

The meaning of the pre-defined subclasses is as follows:

CX_STATIC_CHECK

The class CX_STATIC_CHECK classifies exceptions whose handling is checked by the compiler. If an exception of this category could occur, it must either be handled (using TRY...CATCH) or passed along (using RAISING). At runtime, exceptions of this type only leave the procedure interface if they are declared in the procedure's RAISING clause.

CX_DYNAMIC_CHECK

The class CX_DYNAMIC_CHECK classifies exceptions that are not to be checked statically by the compiler. However, these exceptions can be declared in the RAISING clause of a procedure. If they are, then the exception can pass the procedure interface at runtime, if it has not already been handled locally. At runtime, these exceptions behave in the same way as exceptions in the CX_STATIC_CHECK category, except that they are checked by the compiler at compile-time. These exceptions are particularly well-suited to displaying interface violations.

CX_NO_CHECK

The class CX_NO_CHECK classifies exceptions that are not checked for consistency, either statically by the compiler or dynamically at runtime. Logically, these exceptions cannot be declared in the RAISING clause of a procedure. An exception in this category is always passed along the call hierarchy, until an appropriate handler is found, or - if there is no appropriate handler - a runtime error occurs. These exceptions are particularly well-suited to displaying resource bottlenecks (which can occur in many different places, but which few developers want to deal with).