Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Exceptions (was Type extension, Oberon)

6 views
Skip to first unread message

Eliot Moss

unread,
Apr 3, 1990, 12:53:00 PM4/3/90
to
Chuck Lins said that exceptions are necessary in an asynchronous multi-tasking
environment. I contend that exceptions are a good idea in a synchronous,
single user environment, too. The reason is that they allow unusual and error
conditions to be separated out from the main flow of the program. They also
tend to prevent a problem typical of many Un*x programs: failure to check
result codes for errors. Exceptions are *not* interrupts. And personally, I do
not hold to the Ada view that exceptions are only for error conditions. I
believe that exceptions can quite reasonably be used for unusual situations
that are perhaps more conveniently handled "on the side". See, for example,
the exception mechanism we built for the CLU language, and the way it was
integrated with exits.

Since I wrote my original message, I have obtained copies of some Oberon
articles, and I have not changed my opinion of Modula-3 versus Oberon, but I
recognize that it is an opinion, with which Chuck and anybody else is free to
disagree. I do believe that Modula-3 is more practical because it has defined
more of the facilities needed (in *my opinion*) for constructing large systems
programs. Cheers! Eliot
--

J. Eliot B. Moss, Assistant Professor
Department of Computer and Information Science
Lederle Graduate Research Center
University of Massachusetts
Amherst, MA 01003
(413) 545-4206; Mo...@cs.umass.edu

Chuck Lins

unread,
Apr 6, 1990, 12:18:26 PM4/6/90
to

The failure to test result codes for errors is not solved by adding exceptions.
Now the programmer simply fails to include proper exceptions. The end result
is the same - erroneous and incorrect programs. Adding a language construct
does not address the real issue: programming is a discipline and it takes a
lot of discipline on the part of the programmer to create correct and robust
programs.

Since in the design of a program or software system errors must be accounted
for, I would contend that so-called "unusual" and "error" conditions are in
reality just another part of the normal program flow. In any event, such
conditions must be handled properly by the program. Failure to do so results in
an incorrect program.

This is not a flame against Mr. Moss. We just happen to hold opinions at
oppositie ends of the spectrum on this issue (exceptions vs. no exceptions and
should baggage be added to a language to correct for improper programming
practice). I would be interested in having other join this discussion.


--
Chuck Lins | "Exit left to funway."
Apple Computer, Inc. | Internet: li...@apple.com
20525 Mariani Avenue | AppleLink: LINS
Mail Stop 41-K |
Cupertino, CA 95014 | "Self-proclaimed Object Oberon Evangelist"
The intersection of Apple's ideas and my ideas yields the empty set.

Herb Poppe

unread,
Apr 6, 1990, 1:38:34 PM4/6/90
to

I'll take exceptions any day of the week, thanks.

Maybe we need Oberla, or perhaps Moduron.


Herb Poppe NCAR
hpo...@ncar.ucar.edu 1850 Table Mesa Drive
Boulder, CO 80307-3000
(303) 497-1296

Tom Reid x4505

unread,
Apr 6, 1990, 1:48:40 PM4/6/90
to
> Chuck Lins said that exceptions are necessary in an asynchronous multi-tasking
> environment. I contend that exceptions are a good idea in a synchronous,
> single user environment, too. The reason is that they allow unusual and error
> conditions to be separated out from the main flow of the program. They also
>
> J. Eliot B. Moss, Assistant Professor

The main problem with using exceptions this way is it hide WHERE the
exception occurs. It is akin to the COME FROM (opposite of GO TO) problem.
The advantage is you can see the straight line normal flow of control
better because the validation is not mixed in, however I would always be
leery if the programmer thought of a possible problem if it is not in line.

I once saw an Ada trainer give an example of a simple merge-type program
with about 15 lines of "main" algorithm and about 50 lines of exception
handling (EOL, EOF, etc.). The "REAL" program was impossible to determine
even with this small a program.

The real question is what is "unusual" versus what is "error". I think that
using exceptions in any situation other than having the present context
broken (i.e., the exception returns to a level of control above the
break and not to the normal sequence of control) is a mistake.

Tom.


Thomas F. Reid, Ph. D. (703)818-4505 (work)
Contel Technology Center (703)742-8720 (home)
15000 Conference Center Drive Net: re...@ctc.contel.com
P.O. Box 10814
Chantilly, Va. 22021-3808

David R. Chase

unread,
Apr 6, 1990, 5:21:41 PM4/6/90
to
I tend to the pro-exception camp, with reservations. I've written and
debugged bits and pieces of Modula-3, and written a back-end for a M-3
compiler. The 15-line-normal/50-line-exceptional example
notwithstanding, I have found exceptions to be useful, and I find them
useful because of the way they allow separation of "normal" from "not
normal" cases. In some numerical code that I wrote, it was quite
handy to take care of "failed to converge" and "divide-by-zero" as
exceptional cases. Exceptions also have one useful abuse -- locally,
they do a good job as "structured goto", and a compiler can easily
turn that into a goto and avoid the overhead of exception dispatch.

Exceptions are somewhat better than return codes for construction of
reliable programs, because (Modula-3 semantics) if your code fails to
catch a raised exception, then it blows up ("Uncaught exception --
core dumped"). This doesn't solve the whole problem --
testing/verification of code may still fail to ever raise an exception
that won't be caught -- but it's a lot better than nothing. Plus, in
Modula-3 procedure signatures include declarations of what exceptions
will be raised -- a compiler can (and one does/did) warn of places
where an uncaught exception may occur.

Now, the reservations.

There are holes in this, of course -- the default signature for
Modula-3 procedures is "RAISES ANY", which means that a sloppy
programmer will get little help from the compiler. This was hotly
debated among the Modula-3 committee, and at least one paper was
produced arguing for a default of RAISES NONE. Furthermore, a
TRY-EXCEPT-ELSE-END will catch everything, which may be a bit of
overkill. There's stylistic problems too; at least one person has
argued that the default exception list for extensible packages ought
to be "RAISES ANY" because "who knows what exceptions will be
appropriate to the extensions?" and I don't really have a good
counter-argument.

Some future descendant of the language might steal a bit from the C++
proposals, and either allow some sort of "subtyping" of exceptions, or
go so far as to say that exceptions are just objects (i.e., a
declaration of what exceptions might be raised = a declaration of the
possible types that might be exceptionally returned). This gives some
additional flexibility that might help avoid the use of RAISES ANY.
(DON'T look for this in anything called Modula-3; I'm not on the
committee, but I'm pretty sure of their behavior in this case.)

My biggest gripe concerning exceptions has nothing to do with their
typical use or language semantics. It turns out that it is difficult
to *generate* efficient, reliable object code using either C as an
intermediate language or a C-based backend. People from Xerox say
that it isn't too bad if you just wrap each guarded block into its own
nested procedure (simulated, of course, in C, with a great number of
pointers), but I don't have a great deal of confidence in that (i.e.,
I'd like to see a detailed and thorough comparison). Setjmp+longjmp,
of course, is a flaky option, since that combination rarely combines
correct semantics and speed, and often possesses neither.

It's "just a SMOP" of build an optimizing backend safe for
Modula-3-style exceptions, but it hasn't happened yet. The Acorn
Modula-2+ compiler generated quite acceptable code without any
significant optimizations, however, so maybe this isn't that large a
problem. Do note that their M2+ compiler had its own back-end -- it
just did a good job of generating code.

David

Dan L. Pierson

unread,
Apr 6, 1990, 5:36:20 PM4/6/90
to

On 6 Apr 90 16:18:26 GMT,

li...@Apple.COM (Chuck Lins) said:
> The failure to test result codes for errors is not solved by adding
> exceptions. Now the programmer simply fails to include proper
> exceptions. The end result is the same - erroneous and incorrect
> programs.

I think that you're mixing up two types of errors here:

1. Failure to test error status (a.k.a. return codes, etc.).

This is a very easy error to get with return code checking.
All it takes is one call, anywhere in the call chain, that
fails to correctly test the error status and all higher calls
are broken. This means that in a large project, all it takes
is one careless mistake by one programmer to cause large and
unpredictable consequences for anyone else. In my experience,
such mistakes are made; programmers are human; and systems or
languages that try to assume otherwise will always have
problems.

Exceptions handle this very well because they are guaranteed to
be detected (unless some sort of explict "execute this and
ignore all exceptions" construct is used). Otherwise unhandled
exceptions will result in immediate invocation of a top level
default handler (or a dump, which is frequently the same thing :-)).
They won't cause subtle errors that result in incorrect results
or program crashes in distant places.

2. Failure to generate a correct error status.

I claim that this type of error, while serious, is less common
and easier to detect. Since most routines contain more calls
than returns, it is less work to create the correct code in the
first place (see below for more on this). It is also easier to
inspect code to verify that correct error status is being
generated, than it is to verify that correct error status is
being checked AND APPROPRIATE ACTION TAKEN at every call.

Exceptions don't really change the above at all.

These two types of error come together when error status must
propagate up many levels of calls. With return codes, the error must
be checked and a new error status returned at each and every level.
With exceptions there are many fewer places where error status must be
explicitly handled since the exception will automatically travel up
the call chain until it finds a handler.

Proper exception handling facilties support other common error cases
such as resource cleanup. For example, IMHO the following would be
harder to write, read and maintain without exceptions (please forgive
the clumsy Modula-3, I really want to do this in Lisp):

TRY BEGIN
str := OpenWrite(path);
muckAboutWithFile(str);
END;
FINALLY BEGIN
Close(str);
END;
END;

Note that a non-exception version must guarantee both to close the
file and to return the error status from muckAboutWithFile.

> Adding a language construct does not address the real
> issue: programming is a discipline and it takes a lot of discipline
> on the part of the programmer to create correct and robust programs.

True as far as it goes. However, programming disciplines, techniques,
languages, and support tools which fail to assume that programmers are
fallible human beings are doomed to be costly and less effective than
ones that take human nature into account.

> Since in the design of a program or software system errors must be
> accounted for, I would contend that so-called "unusual" and "error"
> conditions are in reality just another part of the normal program
> flow. In any event, such conditions must be handled properly by the
> program. Failure to do so results in an incorrect program.

Absolutely. However, if you would like to create maintainable and
evolvable programs then language features that minimize the syntactic
noise caused by handling error conditions will have advantages.

Return codes have two very bad characteristics from the viewpoint of
readable and maintainable coding:

1. It is fairly easy (and common in short routines) for the return
code checking to be the majority of the program text. This
clutters up the code and obfuscates its intent.

2. Function return values are too useful for other purposes to be
dedicated to error checking.

In addition, return codes frequently force you to deal with the error
at the wrong point. I claim that one of the reasons many programmers
are so sloppy about checking return codes is that there is nothing
useful they can do with them. For example (abbreviated from a past
life):

You are writing an interactive, end-user application (e.g. think
Macintosh). Down in the bowels of processing a command you try to
allocate some memory. The allocation function returns an out of
memory error. What do you do with it? Aborting is obviously not
an option. The low level function that got the error has no idea
what the overall context is and therefore has no idea what to do.
Maybe a higher processing level could decide to back out, free up
some cache and restart the command with less overall memory use.
Maybe the higher level has give up and to ask the user to close
some files.

With return codes the low level function, and every function above it,
has to be written to consider every possible lower level error and at
least pass it along. Admittedly this frequently degenerates into
blindly passing every error along, but that's also bad.

With exceptions, all of the lower level functions can ignore that
error and higher level functions can include specific handlers for
conditions that they can do something useful about. This will not
especially change the size of complexity of the higher level code
(after all, it had to do that anyway). It can dramatically simplify
the surface of the lower level code, thus making easier and faster to
write, verify, change, and debug.

Please note that I'm not accusing anyone specific of doing the bad
things above. In just my last decade of programming I've seen many
variations of these errors committed by many different programmers.
They really happen. As far as I can tell, they really happen most
everywhere. Programmer training and discipline are part of the
solution, management commitment to spend the time and money required
for design, code reviews, etc. are another part of the solution,
better tools and languages are also an important part of the solution.
--

dan

In real life: Dan Pierson, Encore Computer Corporation, Research
UUCP: {talcott,linus,necis,decvax}!encore!pierson
Internet: pie...@encore.com

Chuck Lins

unread,
Apr 9, 1990, 1:21:18 PM4/9/90
to
In article <35...@brunix.UUCP> d...@cs.brown.edu (David R. Chase) writes:
[well a bunch of stuff deleted, you'll have to read them yourself]

Both Dan and David make good points. One alternative that hasn't been mentioned
yet is implementing a module for exception handling. Such a module requires
a bit of assembly language coding for the implementation but it can (and has)
been done. This is how MacApp(R) implements a signaling exception mechanism
in a language without exception handling features (Object Pascal). This
overhead at run-time is minimal. So you can have an efficient, exception
mechanism in a language without exceptions. BTW, the Metrowerks Modula-2
compiler for the Macintosh(TM) provides just such a module.

Hal Chambers

unread,
Apr 10, 1990, 10:00:48 AM4/10/90
to
In article <40...@apple.Apple.COM> li...@Apple.COM (Chuck Lins) writes:
>Both Dan and David make good points. One alternative that hasn't been mentioned
>yet is implementing a module for exception handling...
>... So you can have an efficient, exception

>mechanism in a language without exceptions. BTW, the Metrowerks Modula-2
>compiler for the Macintosh(TM) provides just such a module.

This is what I REALLY like about Modula-2; the ability to expand/change
its capabilities. I've thought about doing this very same thing (but
haven't had time).

One of the first things I changed about M-2 was the IO. Not liking the
standard IO modules, I wrote my own (software tools inspired). My Modula-2
motto is "If I don't like something; don't complain, change it!".
If only I could find time to get back to a much neglected project; a
full Virtual Operating System.

--
Hal Chambers
h...@newton.physics.purdue.edu
h...@physics-newton.arpa

Mark SOKOLOWSKI

unread,
Apr 10, 1990, 8:50:49 PM4/10/90
to

Hi,

It's my first posting here. I would like to know what's the latest
version of Logitech's Modula-2 compiler (I have currently V3.x, dating
back to 1988). My main concern here is to know if they came up with a
386 version and if it includes graphic libraries for MDA adapters found
on PS/2 70 (The computer on which I'm currently finishing my term project).
I'm in a hurry, so I would like anybody to possibly post me answer very fast.
Thanks in advance...

Michael Franz

unread,
Apr 11, 1990, 7:21:10 AM4/11/90
to
In the Oberon Operating System, much use is made of the controlled exit
facility of the HALT statement. A HALT forces execution of the current
command to stop, resets the stack and returns to the Operating System
Command Loop (as well as opening a viewer containing a symbolic stack dump),
but does not affect the global state of loaded modules. The module
containing the HALT instruction, as well as all other modules, will stay
loaded and its global variables will stay intact. A new command may
then be executed.

Oberon abandons the notion of a PROGRAM altogether. Any module may
export COMMANDS, parameterless procedures, which may be executed
directly from the operating system interface. These Commands take their
parameters from global variables of the OS, which include such items as the
viewer containing the insertion point and a time-stamped list of text
selections.

Granularity of these commands is quite fine. Typical commands display
the directory of a storage device, increase the font size of the text
last selected or compile the contents of the active window. A user may
execute commands in any sequence, and may thus be working on completely
different problems in different windows at the same time (One-process
Multitasking). No difference is made between Commands offered by the OS
and User Commands, which are thought of as extending the basic system.

In this environment, the safe exit via HALT is of course ideal. A HALT
will just terminate the current command; after taking some actions,
the user may try to execute the command again. A typical application
might be a floppy disk driver - if no disk is inserted, it is quite
cumbersome passing up this information to the module originally instructed
to display a disk directory. In Oberon, the disk driver module would
output an error message and execute a controlled halt. The user may
then insert a floppy disk into the drive and retry the command.

-- Michael

Michael Franz Computersysteme ETH Zurich Switzerland fr...@inf.ethz.ch

0 new messages