[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Exceptions (Was: OO2C problem)




Michael van Acken and I have gone back and forth many times about this very
issue.  I have never been completely satisfied with the results, but the
mechanism in module `Exception' does work and is similar to the Modula-2
mechanism.  Michael has been very reluctant to introduce any language
changes (justifiably so), and therefore, we both agree that what we have is
about the best we can do right now.  Until the language report changes, and
introduces a "standard" exception handling scheme, we are pretty much stuck.

"Mark K. Gardner" <mkgardne@rtsl3.cs.uiuc.edu> wrote:
> *** Now for the controversy ***
> 
> The reason why I wanted to use procedure variables in this manner is
> to provide a module in which 1) users can define classes of exceptions
> which can be handled as specific exceptions or as a class, and most
> importantly 2) that the state of the program in the scope of the
> exception is available for examination. What I would like is something
> like
> 
>   PROCEDURE p (...);
>     TYPE
>       BadException = POINTER TO BadDesc;
>       BadDesc = RECORD(Exception.ExceptionDesc)
>         ...
>       END;
>       WorseException = POINTER TO WorseDesc;
>       WorseDesc = RECORD(Exception.ExceptionDesc)
>         ...
>       END;
>     VAR
>       a, b ...
>   BEGIN
>     ...
>     TRY
>       ...
>     CATCH (e : BadException)
>       (* use a, b ... to report or fix the problem *)
>     CATCH (e : WorseException)
>       (* use a, b ... to report or fix the problem *)
>     ELSE
>       (* use a, b ... to report or fix the problem *)
>     END;
>     ...
>     TRY
>       ...
>     END;
>   END p;

The way you would implement the above using module `Exception' is something
like the following:

MODULE ExceptTest;
 
IMPORT
  Exception, Out;
 
CONST
  BadException = 1;
  WorseException = 2;
  
VAR
  src: Exception.Source;
  
  PROCEDURE Counter (c: INTEGER);
  BEGIN
    Out.String ("Entering counter "); Out.Int (c, 0); Out.Ln;
    IF (c = 0) THEN
      Exception.RAISE (src, 1, "[ExceptTest] Counter reached zero")
    ELSIF (c < 0) THEN
      Exception.RAISE (src, 2, "[ExceptTest] Counter less than zero")
    ELSE
      Counter (c-1)
    END;
    Out.String ("Leaving counter "); Out.Int (c, 0); Out.Ln
  END Counter;
 
  PROCEDURE p ();
(********************************************************************
 At this time, there is no provision for extensible exception types.  
 I can see the use of allowing these, but, why are these declared 
 local to p()?  Does this mean p() would RAISE all exceptions itself 
 and nowhere else within the enclosing module?
 
     TYPE
       BadException = POINTER TO BadDesc;
       BadDesc = RECORD(Exception.ExceptionDesc)
         ...
       END;
       WorseException = POINTER TO WorseDesc;
       WorseDesc = RECORD(Exception.ExceptionDesc)
         ...
       END;
*)
     VAR
       a, b: INTEGER;
       e: Exception.Source;
   BEGIN
     a := 5;
     b := -4;
(*   TRY *)
    Exception.PUSHCONTEXT (e);
    IF (e = NIL) THEN  (* normal execution *)
      Counter (a);
      Counter (b);
    ELSE
(*  CATCH (e : BadException) *)
      IF (Exception.CurrentNumber(e) = BadException) THEN
        Out.String ("Caught bad exception"); Out.Ln;
        Exception.ACKNOWLEDGE
(*  CATCH (e : WorseException) *)
      ELSIF (Exception.CurrentNumber(e) = WorseException) THEN
        Out.String ("Caught worse exception"); Out.Ln;
        Exception.ACKNOWLEDGE
      ELSE
        (* use a, b ... to report or fix the problem *)
      END;
    END;
    Exception.POPCONTEXT;  (* clean up or be damned *)    
   END p;

BEGIN
  Exception.AllocateSource (src);
  p();
END ExceptTest.

Yes, it is somewhat awkward, ugly, and error prone, but that's about all we
can do without changing the language.  

If you want to talk about changing the language, my current suggestion is
for providing more language support for our current mechanism: adding
keywords EXCEPT and RETRY (ala XDS), and possibly a "standard" exception
type that could be extended to build classes of exceptions.

Examples:

(* rewrite of p() from above *)

  PROCEDURE p ();
   VAR
       a, b: INTEGER;
   BEGIN
     a := 5;
     b := -4;
     Counter (a);
     Counter (b);
   EXCEPT
     IF (IsCurrentSource(src)) THEN
       IF (Exception.CurrentNumber(src) = BadException) THEN
         Out.String ("Caught bad exception"); Out.Ln;
         RETURN 
         (* a return implictly ACKNOWLEDGEs the exception *)
       ELSIF (Exception.CurrentNumber(src) = WorseException) THEN
         Out.String ("Caught worse exception"); Out.Ln;
         RETURN
       END
     ELSE
        (* use a, b ... to report or fix the problem *)
     END;
   END p;

(* Or if module `Exception' provided an extensible exception type, and types
   `BadException' and `WorseException' were extended from it.
*)

  PROCEDURE p ();
   VAR
       a, b: INTEGER;
       e: Exception.Exception;
   BEGIN
     a := 5;
     b := -4;
     Counter (a);
     Counter (b);
   EXCEPT
     e := Exception.GetException();
     WITH 
	e: BadException DO
	  Out.String ("Caught bad exception"); Out.Ln;
          RETURN
     |  e: WorseException DO
          Out.String ("Caught worse exception"); Out.Ln;
          RETURN
     ELSE
        (* use a, b ... to report or fix the problem *)
     END;
   END p;


The mechanism proposed by Mossenbock, et. al., is slick, but I have a
problem with it.  There is no real difference between a regular local
procedure and an exception handler.  This could cause confusion, especially
if someone used odd naming conventions.

Example:

MODULE X;
...
TYPE
   BadName = POINTER TO BadNameDesc;
   BadNameDesc = RECORD(Exception.ExceptionDesc)
         ...     
   END;

   PROCEDURE Y;
      PROCEDURE Z(b: BadName);  (* It's not obvious that Z is an exception
                                   handler *)
      ...
      END Z;
   ...
   END Y;
      

I think it would also confuse newcomers to the language and anyone not
familiar with metaprogramming.  (We could actually probably implement such a
thing without metaprogramming, but that's beside the point).  It just seems
too much like magic unless you really know what is going on.  On the other
hand, an explict EXCEPT block is more obvious.

Eric
-- 
___________________________________________________________________________
           Eric Nikitin              |   When thou wakest, let love forbid
    _Into the Realm of Oberon:       |   Sleep his seat on thy eyelid:
 an Introduction to Programming and  |   So awake when I am gone;
 the Oberon-2 Programming Language_  |   For I must now to Oberon.
       ISBN:  0-387-98279-5          |       
     http://www.springer-ny.com      |       -- A Midsummer Night's Dream
___________________________________________________________________________