From: rmartin@thor.Rational.COM (Bob Martin)
Subject: Re: Complexity in the eyes...V2.0
Keywords: error errorstack
Organization: Rational
Date: Wed, 23 Dec 1992 16:23:23 GMT

andrew@tagsys.com (Andrew Gideon) writes:

|If I understand your proposal, you'd have me add an ordered collection
|of "parameters" to the base error atom class?  Interesting thought.

|Well, let me describe my vision of the error atom - something that I
|stayed away from in previous posts.

|The base error atom class ErrorAtom provides virtual methods
|like theSeverity(), theMessage(), isWarning(), etc.  Each module
|(or some other partition of code) provides a subtype of the error
|atom for a specific domain of errors.  

|So instances of the DeviceErrorAtom class might contain a severity
|value and an offset into an array of error messages.  This array would
|be a class member (static member).  This provides for easy copying of
|atoms, nicely partitioned error spaces, a good starting point for user
|documentation, etc.

I was responsible for the error system in a project about a year ago.
There were several similarities between what you describe and what I
implemented.  I had a base class called Error.  Error was a concrete
class, but could not be constructed in the "Errored" form, it could
only be constructed in the "OK" form.  It offered an operator void* as
in iostream so that you could use the following syntax

	Error myError;
	.....
	if (myError)
		.....

Users of Error subclassed their own type of errors.  Each subclass was
associated with an unique id code which effectively identified an
array of error messages.  The constructor for these subclasses
required an argument which was the identifier of the error.
Effectively, this was the index of the error message within the array
belonging to that subclass.

So, an error might be declared as follows:

FileError ferr(CANT_OPEN);

Arguments could be added to errors using operator<<, thus:

ferr << fileName; // add the file name
ferr << errno;    // add the o/s error code.

There was no limit to the number of arguments that could be added.  

Error messages were designed so that they could be supplied in
dictionaries.  The idea was that the product might have to be shiped
to many different countries, and the errors might need to be written
in different languages.  In order to format the errors and their
arguments we invented a sprintf-like syntax for embedding the
arguments into the errors.  i.e.

	"The file: %1s could not be opened due to error code %2d."

Note the digit which specified the ordinal position of the argument.

The class Error allowed copy semantics, so that you could create a
FileError but return it as an Error.  Thus Error object could be
passed up the calling or exception chain without the higher levels of
the code knowing the kind of error.  You could also create vanilla
errors and use assignment to copy a derived error into it.

	Error err = ferr;

Lastly, we created the concept of an ErrorManager.  An ErrorManager is
an object which knows what to do with an error.  Some errors should be
logged to a file, others posted in dialog boxes in a gui.  Still
others should be written to standard error.  Thus we created
subclasses of ErrorManager that know how to interpret an error and
then output it.  Thus the syntax:

	ErrorManager em;
	Error err;
	em.Raise(err);

This would tell the ErrorManager em to output the error err.
Subclasses of ErrorManager such as LogErrorManager or GuiErrorManager
would be created by the highest levels of the code and then passed
down to the middle levels where errors were raised.  Errors would
percolate up from the low levels of the code to these middle layers
and be raised.  This allowed us to link libraries which raised errors
into applications which were gui driven, console driven or batch jobs
which logged errors.  

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The upshot of all this is that, for some applications complex error
management is a necessity.  For such applications, it is best if the
complexity is encapsulated far away from the users of the error
system.  In our case, users could create and raise errors with
relative ease.  They had lots of flexibility to add arguments to their
errors.  But the burden of managing and disposing of the errors was
well encapsulated.






--
Robert Martin                        Training courses offered in:
R. C. M. Consulting                       Object Oriented Analysis
2080 Cranbrook Rd.                        Object Oriented Design
Green Oaks, Il 60048 (708) 918-1004       C++