error

© 2005,2008,2010,2015,2020 John Abbott, Anna M. Bigatti
GNU Free Documentation License, Version 1.2



CoCoALib Documentation Index

Examples

User documentation

The standard way of reporting an error in CoCoALib is to call the macro CoCoA_THROW_ERROR which will create and throw an object of type CoCoA::ErrorInfo. This type is derived from CoCoA::exception (see exception).

If you want to throw a CoCoA exception EXC, we recommend doing so via calling ThrowException(EXC); the advantage with this approach is that the (template) function calls JustBeforeThrowing() which can be intercepted easily in a debugger (e.g. gdb).

Debugging

If you get a CoCoA ERROR when you execute your program, recompile CoCoALib with the configure option --debug, then you can easily intercept the throwing of the exception with your preferred debugger tool.

For example, when debugging with gdb, type

  break CoCoA::JustBeforeThrowing

and then run. When it stops in the call of JustBeforeThrowing, type up (possibly repeatedly to reach the line which originally caused the error.

Recommended way of reporting errors

Usually if you have detected an error in your program, you want to report it immediately. We recommend that you use the macro CoCoA_ERROR to do this. Here's an example:

      value_t operator/(const value_t& num, const value_t& den)
      {
        if (IsZero(den))
          CoCoA_THROW_ERROR(ERR::DivByZero, "operator/ for value_t");
        ....
      }

The first argument should be an error ID (i.e. ERR::something); you can find a list of the IDs in the file (CoCoA_ROOT)/include/CoCoA/error.H. If no ID is suitable, you can just put a string instead. The second argument should be an indication of the function in which the error occurred.

Adding a New Error ID and its Default Message

If you are a CoCoALib contributor and want to add a new error ID and message (or even a new language for error messages), please read the maintainer documentation for what to do.

Information about errors -- for the more advanced

The macro CoCoA_THROW_ERROR does two things:

Below we explain these two stages in more detail.

The class CoCoA::ErrorInfo is intended to be used for creating exception objects -- indeed, it derives from std::exception. There are two things you are likely to want to do with exception objects:

NOTE: if you set the C++ preprocessor symbol CoCoA_DEBUG to a value greater than 1 then a log message is produced each time CoCoA::ThrowError is called; the log message is printed on std::clog.

Recall that, as for any other "exception object", simply creating a CoCoA::ErrorInfo object does not cause the error condition to be signalled. To signal the error it must be thrown -- we recommend passing the error object to the function CoCoA::ThrowError (see above).

Choosing the language for error messages

You may choose the language for CoCoALib error messages: the default is English. If an error message has not yet been translated into the chosen language then it is replaced by the default english message. Currently there are only two choices:

   ErrorLanguage::english();
   ErrorLanguage::italian();

EXAMPLE:

    int main()
    {
      CoCoA::ErrorLanguage::italian(); // vogliamo messaggi d'errore in italiano
      ....
    }

The language for error messages may be changed any number of times: the last chosen language is the one used when creating an ErrorInfo object.

Maintainer documentation for files error.H and error.C

CoCoA::ErrorInfo is derived from std::exception for compatibility with the rest of C++. How this might be useful I cannot yet say, but it does not measurably complicate the code (though it does force the implementation of a member function called what).

The preferred constructors for ErrorInfo are those accepting an ERR::ID and a C string indicating context (with or without filename and line number information); the other constructors should be used only when no suitable ERR::ID exists. The ERR::ID object indicates the general nature of the error, and is used for selecting the error message to be printed.

Note that the conversion from an ERR::ID to a string is slightly convoluted: this is to allow the possibility of selecting at run-time a language other than English for the error messages.

I chose not to offer an ErrorInfo constructor which accepts natively const char* args because the potential extra copying of strings (to construct a std::string) is hardly likely to be important, and std::strings feel much cleaner.

The nature and context of the error are kept separate in an ErrorInfo object since it is possible that we may wish to propagate the nature of the error to top level in an interactive system where it would be unhelpful or confusing to refer to some C++ function irrelevant to the user.

The definition of the function CoCoA::ThrowError is quite straightforward. The function is deliberately not inline: efficiency is wholly unimportant whereas the ability to set a breakpoint in the function is (some debuggers may be unable to set a breakpoint in an inline function).

Each CoCoA error ID object is in reality a constant global variable containing two pointers to constant C strings called myName and myDefaultMesg: the latter contains the associated default error message (which must be in English), and the former contains the name of the error ID object. The identity of the error ID actually resides in the address of the specific string constant in the data member myName -- this implies that copying the ID object does not change its identity. Since the different objects necessarily have different names, the string literals containing those names are surely distinct, and so we are guaranteed that these addresses are distinct. There are comparison operators (equal, not-equal, and less-than) for ERR::ID; less-than is needed for using C++ maps when implementing error messages in languages other than english. These comparison operators merely conduct the required comparison on the addresses of the strings in myName; this is quick and simple, and sufficient for our purposes -- the actual values of strings pointed to are not taken into consideration!

To Add a New Error Code and Message

Invent a new name for the error code, and insert it in the list of names of "error variables" (in the file error.H). Make sure you insert it in the right place respecting alphabetical order -- this way it is easy to check whether a name is already present in the list. Add a short comment indicating what sort of error that code is to be used for.

Next you must add a message corresponding to that code. In the file error.C you will find a long list of "error variable" initializations. Add an initialization for your new "error variable" -- the syntax is quite obvious from the other initializations there (which use the macro DEFINE_ERROR). You may wish to add translations of your new error message into the other languages present in error.C.

To Add a New Language for Error Messages

You must write a function analogous to the function italian() which resides inside the namespace CoCoA::ErrorLanguage. The new function must have a name different from the other functions there: I suggest the english name of the language. Inside the function you will have to fill a MsgTable_t object with the translated messages associated to each possible error code. At the end you should check to make sure that you have a message for each possible code: it should suffice simply to count them. The code will still compile and run even if some translated messages are missing: if an error occurs for which the current error language has no translation then the default (english) message is printed.

EXAMPLE: Suppose we want to add german error messages. We choose to use the name "german" for the function which activates german error messages. Here is what we do:

(1) edit error.H;
immediately after the line containing "void italian();" insert "void german();"

(2) edit error.C;
make a copy of the function italian(){...} and change its name to "german" -- make sure you stay inside namespace ErrorLanguage; translate all the error messages in the strings.

Bugs, Shortcomings, and other ideas

The throw specifications on the destructor and what member function are needed for compatibility with std::exception -- I regard this as a nuisance. I wonder if std::string::c_str can throw?

What about parameter values? In some cases it would be handy to give the bad value which caused the error: e.g. "Bad characteristic: 33". A problem is that a parameter value could be very large. We could simply allow up to 100 (say) characters of parameter information in a suitable string.

Only very few error messages have been translated into italian so far.

Perhaps allow the user to specify which ostream to print the logging message in ThrowError?

new improved list of errors

work in progress

Main changes

2013