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

a safer and more efficient exception system



   Date: Wed, 24 Apr 1996 16:11:44 +0000
   From: William D Clinger <will@ccs.neu.edu>
   > ...  If two exception types
   > have incompatible argument conventions you cannot make a new
   > type that is a subclass of both.  Or rather, you can make it
   > but handlers for the superclasses will break when they get an
   > instance of the new class.

   I think this is the most serious problem with my rearrangement
   of Kelsey's proposal.  I also don't think it is very serious.

I think this is actually a -very- serious deficiency -- but if you read
through to the end of this message I will make a suggestion that should
make things more tolerable (I think).

Recall the following example given in an earlier message from Kelsey (he
attributes the example to Pitman):

 Suppose you have a distributed file system and you can't open
 a port on a remote file because the ethernet is not responding.
 For file systems there is a FILE-CREATION-FAILURE condition and
 for networks there is a TEMPORARY-NETWORK-OUTAGE condition.
 Neither is a subtype of the other, they have different recovery
 options (trying another name vs. waiting for the network to
 come back) and both are equally appropriate for the current
 situation.  With multiple inheritance you can signal both
 simultaneously.

In this situation, the FILE-CREATION-FAILURE exception (to adopt your
terminology) will almost certainly want to include the pathname of the file
that couldn't be created.  Similarly, the TEMPORARY-NETWORK-OUTAGE
exception will almost certainly want to include the network address that
wasn't responding.  Having that information available to whatever handler
gets selected is extremely important.

Now in your proposal, your -condition- objects can support a kind of
multiple inheritance of slots (using symbols to name the slots), but I
don't see any useful way to take advantage of this.  By the time you get
around to calling MAKE-CONDITION, you're already inside an exception
handler, and the only information you have to work with is the -positional-
arguments that were passed to it (as originally passed to SIGNAL).

So now I'm very disappointed because it seems like you're aiming for a
exception system that may solve the problems Will Clinger wants
to solve (you seem very concerned about using exceptions to do things like
fast generic arithmetic), but it doesn't solve the problems Alan Bawden
wants to solve (I want to recover gracefully from errors).  But then you
surprise me by writing:

   Not all exceptions can be used as superclasses for multiple
   inheritance.  The handlers for exceptions that can be so used
   should take a condition (or some other data type that can
   handle multiple inheritance) as their argument.  Storage
   allocation will be required when signalling these exceptions,
   but will not be required when signalling an exception that cannot
   be used as a superclass for multiple inheritance.

Here, buried where I almost missed it, you suggest a solution (almost) to
my problem!  If I use alists (a data type that can handle multiple
inheritance) as the second argument to SIGNAL calls when signalling both
FILE-CREATION-FAILURE and TEMPORARY-NETWORK-OUTAGE, as in:

  (signal file-creation-failure `((pathname . ,pathname)))

and

  (signal temporary-network-outage `((network-address . ,network-address)))

then I can also do:

  (signal temporary-network-outage-file-creation-failure
          `((pathname . ,pathname)
            (network-address . ,network-address)))

and handlers for FILE-CREATION-FAILURE and TEMPORARY-NETWORK-OUTAGE will
-both- be able to cope.

[ Note: I think you were actually suggesting that I write:

    (signal temporary-network-outage-file-creation-failure
            (make-condition temporary-network-outage-file-creation-failure
                            'pathname pathname
                            'network-address network-address))

  but I decided to take your parenthetical remark about "or some other data
  type..." seriously because I don't actually see that the condition data
  type is delivering any additional abstraction advantage -- it's mostly
  just a set of name/value pairs, and we -already- have a way to represent
  those in Scheme!  (We added ASSQ to the standard for a reason, right?) ]

So here's my suggestion.  I would like to require that the second argument
to SIGNAL (i.e. the one immediately after the exception) must -always- be
an alist.  Furthermore, handlers for -most- exceptions should expect -all-
additional contextual information to be bundled up in that alist.  Only a
few carefully chosen exceptions should be signaled with any positional
arguments at all (and they'll still pass an alist argument -- quite
probably the empty list).

This will slow down the exceptions that you (Will) want to be blazingly
fast by whatever it costs to pass an additional null argument.  In return,
it will be much more likely that two exceptions that a user needs to mix
together will in fact be compatible.

It also requires more work from the standards committee.  We will have to
make a decision for each and every standard exception about how its
handlers are to be called.  But actually, we're going to be making a -lot-
of little decisions about those standard exceptions (if we ever get around
to it!)  -- I doubt this adds significantly to the burden.

				- Alan