[comp.lang.pascal] Messy Stuff

storm@cs.mcgill.ca (Marc WANDSCHNEIDER) (04/18/91)

Good Morning.

I am currently writing a program, and in a bit of a quandery over what to
do over error handling.

What I want to do is something like the following:

begin
	procedure
        if not Error, continue
        procedure
        if not Error, contineu
        procedure
        if not Error, continue...
etc...
end.

However, the only way I've come up with so far to do that is have all 
procedures in fact be functions which return a so called "ErrorCode".
The main program then does an IF to see if it's 0 (no error), and otherwise
won't let it continue.

Is there a way to do this somewhat more efficiently, or is my MAIN stuck
with IF THEN ELSE mania....?

./*-
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
storm@cs.mcgill.ca         McGill University           It's 11pm, do YOU
Marc Wandschneider         Montreal, CANADA            know what time it is?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

dmurdoch@watstat.waterloo.edu (Duncan Murdoch) (04/18/91)

In article <1991Apr17.235717.7580@cs.mcgill.ca> storm@cs.mcgill.ca (Marc WANDSCHNEIDER) writes:
>I am currently writing a program, and in a bit of a quandery over what to
>do over error handling.
...
>However, the only way I've come up with so far to do that is have all 
>procedures in fact be functions which return a so called "ErrorCode".
>The main program then does an IF to see if it's 0 (no error), and otherwise
>won't let it continue.
>
>Is there a way to do this somewhat more efficiently, or is my MAIN stuck
>with IF THEN ELSE mania....?

Error handling always ends up messy.  I've seen several solutions, but
they're all a bit ugly:

 - maintain a global "status" variable.  If an error occurs, set it to
a non-zero value.  If you want to do it really well, hide the variable,
make its value only available by a function call (like IOResult) which
resets it, and make all your procedures fail if it's non-zero.

 - code your procedures as boolean functions or functions returning a 
status, and embed all of them in a single big procedure.  Use "exit"
to bail out if an error occurs:

  if not Proc1 then
    exit;
  if not Proc2 then
    exit;
  if not Proc3 then
    exit;

etc.  The problem with this is that the Procs may set something up that
needs cleaning up later; if that's the case, you need something like:

  if Proc1 then
  begin
    if Proc2 then
    begin
       ...
       CleanUpProc2;
    end;
    CleanUpProc1;
  end;

There are other more complicated schemes to bail out, but I've never needed
them.  

Duncan Murdoch
dmurdoch@watstat.waterloo.edu

nmouawad@watmath.waterloo.edu (Naji Mouawad) (04/18/91)

In article <1991Apr17.235717.7580@cs.mcgill.ca> storm@cs.mcgill.ca (Marc WANDSCHNEIDER) writes:
>I am currently writing a program, and in a bit of a quandery over what to
>do over error handling.

>However, the only way I've come up with so far to do that is have all 
>procedures in fact be functions which return a so called "ErrorCode".
>The main program then does an IF to see if it's 0 (no error), and otherwise
>won't let it continue.

>Is there a way to do this somewhat more efficiently, or is my MAIN stuck
>with IF THEN ELSE mania....?

You may want to consider the following:

Divide the errors into -fatal, -global, and -local. By that I mean,
that errors that may lock-up the system, or crash it are fatal, other
errors from which it is possible to recover can be global to all your
procedures or local to each of them.

Have one fatal error procedure, one global and a set of local ones.

A fatal error should trigger a clean-up mechanism, followed by a
message to the user and a shut-down (halt).

A global error can occur mostly anywhere and as such should reside
in the global error engine. There, a prompt to the user should be
made followed by whatever action necessary.

A local error exist only for specialized types of actions and as such
should be attached to the routine where it originates from.

Finally, have two global variables, ErrorClass and ErrorType and an
ErrorDispatcher which relies on them. You could call ErrorDispatcher
with no If statement since this procedure will either exit immediatly
if the ErrorClass is say 'NoError' or follow the appropriate path.

By breaking down the errors you can distribute them accordingly to
their nature. It makes the code safer since every routine will
transport its own error recovery mechanism via the local engine and
easier to maintain since you don't need to write a big case
statement dealing with all possible errors.

A word of caution: Error recovery could be very time consuming and
sometimes can turn into a simili-expert system :). Know how much you
want to `recover from' before hand.

Finally, If OOP was invented for one thing, it was invented for
Error Recovery.

Hope this help even though I did not give precise examples.

--Naji.
-- 
     -------------------------------------------------------------------
    | Naji Mouawad  |          nmouawad@watmath.waterloo.edu            |
    |  University   |---------------------------------------------------|
    | Of Waterloo   |   "The Stranger in us is our most familiar Self"  |

John G. Spragge <SPRAGGEJ@QUCDN.QueensU.CA> (04/26/91)

Assume your procedures are called first, second, third, etc.,
try the following:

VAR
   cc    :   INTEGER;               { counter }
   err   :   BOOLEAN;               { error flag }

BEGIN
   err := false;
   FOR cc := 1 TO 5 DO
       IF NOT err THEN
           CASE cc OF
               1 : first (err);
               2 : second (err);
               3 : third (err);
               4 : fourth (err);
               5 : fifth (err);
           END;
END.

sture@mdivax1.uucp (John Sture) (05/03/91)

Has anyone tried to call TPW units from BC++ for WIndows app's?