Objective-C Issues

exception-handling

People ( From: lines )
 billb@jupiter.fnbc.com (Bill Burcham)
 bradcox@sitevax.gmu.edu (Brad Cox)
 rms@gnu.ai.mit.edu (Richard Stallman)
Subjects ( 7 mails )
 Action Expressions (exception handling, multitasking)
 action expressions
 exceptions
 exceptions
 Re: exceptions
 Re: exceptions
 exceptions
Document
Paul Murphy  just forwarded this to me.  FYI.  10/14/92 gsk

Position Paper
ECOOP'91 WORKSHOP ON
EXCEPTION HANDLING AND OBJECT-ORIENTED PROGRAMMING
July 1991
Geneva, Switzerland

Brad Cox
203 426 1875
cox@stepstone.com
CI$ 71230,647
The Stepstone Corporation
75 Glen Road
Sandy Hook CT 06482

This consists of selected sections from a much longer paper,
`TaskMaster', which discusses a number of environmental features,
including exception handling and lightweight multi-tasking, that can
be supported in any C-based language with a single uniform language
extension called `action expressions'.

The first section of this document discusses exception handling as a
topic unto itself. The final section introduces action expression
syntax and semantics, as is being considered for adoption as an
extension to the Objective-C programming environment.

Exception handling

Consider a subroutine, main(), which calls foo(), which calls bar().
The runtime stack that underlies the C runtime environment extends to
record that main has called foo and that foo has called bar. Then it
retracts as bar returns to foo and as foo returns to main. The same
call/return path is used unconditionally, regardless of whether the
subroutines ran successfully or failed because of an exception.

The absence of a way of handling exceptions explicitly, independently
from normal processing, is a severe obstacle to software quality and
reusability. Since subroutines routines return the same way,
regardless of whether they succeed or fail, a method that should
return a handle to a new object might instead return an error code to
indicate that it could not, perhaps because of insufficient memory.
Since any such call might fail, the caller must check every return
value, reporting any failures to higher levels with similar means.
This is sufficiently tedious that it is neglected, allowing unhandled
exceptions to crash the application.

An `exception' is a situation where a computation does not proceed as
planned, perhaps because of I/O errors, inability to allocate a new
object because of insufficient memory, or defects in the software
itself. `Exception handling' is a language/environmental feature that
reserves the normal subroutine/message return channel exclusively for
normal processing. Routines that return normally can be assumed to
have succeeded, since those that fail will return via a independent
channel reserved for exceptions. Low-level routines never fail by
returning an error code for the caller to decipher, but by `raising an
exception'. Higher level routines establish code fragments, `exception
handlers', that will receive control if the exception they are to
handle is raised by a lower-level routine.

The following shows how exception handling might be done in C, in
order to show the limitations of this solution and how these
limitations are addressed in TaskMaster. TRY() is a C macro that uses
setjmp() to record the machine's register settings before entering the
computation that might fail; the foo subroutine.

main() {
	TRY() {
		int v = foo();
		aGlobal, c->aFormal, c->aLocal, formalArg);
}
foo(aFormal) {
	extern int aGlobal;
	int aLocal;

	

In Re: Your mission, should you choose to accept it. . Bruce Nilo
 writes

NeXT has half heartedly implemented an "Exception Handling" facility.  
It basically consists of some macros, and the use of setjmp() and  
longjmp(). An error handling facility should be specified,  
implemented, and adhered to throughout the runtime system.

I agree wholeheartedly! I joined this list primarily to encourage
extensions to Objective-C of precisely this nature.

I made substantial progress on the run-time part of this problem at Stepstone
several years ago, but never managed to complete the language extensions
(upwards compatible) to make them broadly useful. 

 "Action expressions in Objective-C are similar to
block expressions in Smalltalk, with differences to adapt to the
constraints of stack-based languages like C. Action expressions are a way
to express actions, or deferred computations; computations to be written at
one place but invoked from another."

This document, which describes the (implemented) runtime components and
(unimplemented) syntactic extensions, would be useful in considering
language and/or runtime extensions. 

I'll be glad to email a copy to those planning to  work on such extentions. 
(Please...only if you're planning to do actual work!)
===
Brad Cox, Ph.D; Program on Social and Organizational Learning; George Mason
University; Fairfax VA 22030; 703 691 3187 direct; 703 993 1142 reception;
bradcox@sitevax.gmu.edu
---
Information Age Consulting; 13668 Bent Tree Circle #203; Centreville VA
22020;           703 968 8229 home; 703 968 8798 fax; bradcox@infoage.com

Date: Thu, 15 Oct 92 04:59:00 -0400
From: rms@gnu.ai.mit.edu (Richard Stallman)
To: gsk@marble.com
Cc: gnu-objc@prep.ai.mit.edu
Subject: action expressions

GNU C supports nested functions.  In 2.3, these should work in
Objective C.  This supplies most of the mechanism for creating action
objects if you want them.  In fact, I expect one can go the rest of
the way with macros, if you don't mind a different syntax:

#define make_action(name, body)
 ({ id __temp = ;
    void name () { body }
    ;
    __temp; })

I've omitted the backslashes, and left stubs for where Objective C
constructs are needed since I don't know them.

This technique requires you to give a unique name each time you write
an action expression.  That could be avoided with an improvement in
macro power.

Date: Thu, 15 Oct 92 05:02:24 -0400
From: rms@gnu.ai.mit.edu (Richard Stallman)
To: gsk@marble.com
Cc: gnu-objc@prep.ai.mit.edu
Subject: exceptions

There seems to be a concensus that (1) exceptions should work by
exiting to the level where the handler was set up, and (2) running a
debugger is a completely independent matter from handling exceptions.

I've seen systems where there was an attempt to permit handlers to
look at the environment of the exception.  The problem is that the
handler can't do anything useful except a goto, unless it understands
what was going on at the place that got the exception.  And the whole
idea is that the handler shouldn't have to know that.  So an exception
facility that always does a goto is sufficient.

There are various plans to implement exception handling in GCC for the
sake of various languages, and it will surely get done sooner or later.
It will be easy to support in Objective C once the mechanism is present.

Date: Thu, 15 Oct 92 05:25:13 -0400
From: rms@gnu.ai.mit.edu (Richard Stallman)
To: rms@gnu.ai.mit.edu
Cc: gsk@marble.com, gnu-objc@prep.ai.mit.edu
Subject: exceptions

I see my message was not clearly written and might have been
confusing.

There seems to be a consensus among most language designers that (1)
exceptions should work by exiting to the level where the handler was
set up, and (2) running a debugger is a completely independent matter
from handling exceptions.  Brad Cox seems to disagree--but I agree
with the general consensus, and that's how I plan to support
exceptions in GCC.

Date: Thu, 15 Oct 1992 08:15:44 -0500
To: rms@gnu.ai.mit.edu (Richard Stallman)
From: bradcox@sitevax.gmu.edu (Brad Cox)
Subject: Re: exceptions
Cc: gsk@marble.com, gnu-objc@prep.ai.mit.edu

>There seems to be a consensus among most language designers that (1)
>exceptions should work by exiting to the level where the handler was
>set up, and (2) running a debugger is a completely independent matter
>from handling exceptions.

The problem is most obvious when designing a 'default' exception handler;
i.e. a piece of code internal to the EH package that will automatically
catch exceptions globally if the programmer doesn't provide one of his own.

This global handler needs to run in the context of the exception to, for
example, print a backtrace showing the calls that led to the exception. The
same applies if somebody wants to override the exception to call a more
sophisticated process inspector ( a 'debugger'), perhaps capable of
examining and possibly even changing global shared state (such as the
stack) and maybe even resuming the execution. For example, imagine invoking
adb (or something better) from inside the handler.

I suspect that the concensus you speak of arose from the difficulty of
writing exception handlers as subroutines rather than from more considered
reasons. Action expressions are useful for many other things than exception
handling. But once they become available, it becomes practical to
reconsider solutions that weren't practical in their absence...like running
exception handlers as subroutines of the exception. That is, exception
handlers often need to access state  local to the scope of the calling
site. This is clumsy if the handler is a subroutine, but easy if the
handler is an action object because all variables are copied into the
action object and passed to its handler as ordinary variables.

I've advocated a departure from concensus on this matter on the grounds of
generality...potentially useful (albeit nontrivial to access) information;
i.e. stack frames, are unconditionally discarded in the concensus solution
that is retained by the action expression approach. 

And oh yes, the concensus approach is a concensus only for compiled
stack-based languages like C, but not for non-stack-based languages like
Smalltalk and (although I'm less sure of this; any Lisp experts in the
crowd?) and Lisp. 
Brad Cox; 703 691 3187 direct; 703 993 1142 reception;
bradcox@sitevax.gmu.edu

From: billb@jupiter.fnbc.com (Bill Burcham)
Date: Thu, 15 Oct 92 09:59:06 -0500
To: bradcox@sitevax.gmu.edu (Brad Cox)
Subject: Re: exceptions
Cc: gnu-objc@prep.ai.mit.edu

Yeah, and there are also the problems of breaking a thread and never
getting back from traditional exceptions.  Also, NeXT's approach uses
int's to identify exceptions -- but they have no object to manage the
allocation of these ints, so if I write some reusable class, I have to
pick an int range at random (and pray that no one else has used or
will ever use any of those same ints for their exceptions).

If we choose the consensus scheme (not that I am saying we _should_), then I believe it is important to provide an ExceptionBroker:

+ (BOOL)setCodeBase:(int)base availableExceptions:(int)howmany;
+ registerErrorReporter:(void (*)(NXHandler *errorState))proc
	forException:(STR)aName;
+ raise:(STR)exception data1:(void*)data1 data2:(void*)data2;
+ (BOOL)senderMayRaise:(STR)aName;
+ (int)exceptionNumber:(STR)aName;
	
#define EB_RegisterErrorReporter(proc, name) \
[ExceptionBroker registerErrorReporter:(proc) \
	forException:(aName)]
	
#define EB_RAISE(exception, d1, d2) \
[ExceptionBroker raise:(exception) data1:(d1) data2:(d2)]

This protocol allows a class which will raise certain exceptions (or
will produce instances which will produce certain exceptions) to check
in +initialize (or -init) whether or not those exception identifiers
are available to it.  If they are not, then the class or instance can
set an ivar such as `BOOL classIsBroker' which can prevent subsequent
instantiation, etc.

I will donate ExceptionBroker and helper class Exception to The
Project if anyone is interested.

Bill

Date: Thu, 15 Oct 92 15:00:35 -0400
From: rms@gnu.ai.mit.edu (Richard Stallman)
To: bradcox@sitevax.gmu.edu
Cc: gsk@marble.com, gnu-objc@prep.ai.mit.edu
Subject: exceptions

    I suspect that the concensus you speak of arose from the difficulty of
    writing exception handlers as subroutines

The difficulty you speak of is limited to C.  Most of the language
design I'm talking about is for other languages that support nested
functions, and could easily use that mechanism for running an
exception handler as a subroutine, if that were desired.  There used
to be such designs, as in PL/1, but they were not very useful and that
led to the conclusion that handlers should always go back to the
context where they were set up.

    This global handler needs to run in the context of the exception to, for
    example, print a backtrace showing the calls that led to the exception.

The second part of the consensus is that handlers should not be the
basis for debugging.

It is not very useful to print a backtrace.  The ways we deal with
crashes is by either stopping the process or by making a core dump.
Either way, you can get a backtrace or do various other useful
things.  The way to do these is not with a handler.  Instead, the
function that raises an exception will raise a signal when
appropriate.


I'm not going to support more than one exception handler mechanism in
GCC unless there is a clear need.  I want to support just one, for all
languages--to save work.  It may be that this mechanism can handle
handlers that run as subroutines as well as handlers that jump,
without much extra trouble.  But I would still design the handler
construct in a new language to do jumps, at this point.

Statistics
 filename:           exception-handling
 number of mails:    7
 number of writers:  3
 line count:         604
 word count:         3991
 character count:    25993

created by Helge Hess ( helge@mdlink.de )
MDlink online service center ( www.mdlink.de )