Why exceptions shouldn't be used for flow control [Re: YAS to the "Reading line-by-line" Problem]

Tres Seaver tseaver at palladion.com
Thu Jun 24 05:18:00 CEST 1999

William Tanksley wrote:
> On Thu, 24 Jun 1999 11:55:35 +1200, Greg Ewing wrote:
> >William Tanksley wrote:
> >> Both should be handled by exception, not by returning a special
> >> value.
> >I don't agree with that. Reaching the end of a file while
> >reading it is not exceptional enough to warrant requiring
> >the use of an exception handler to catch it.
> "Not exceptional enough".  What does that mean?  (I ain't never had too
> much exception! ;-)
> It's an exception to the behavior of a function defined to return the next
> entity in a file.  It's not an exception to a function which returns the
> next entity, or some reserved value otherwise.  There's no such thing as a
> partial exception; it's a quality, not a quantity.

In Design-by-Contract terms, a service may throw exceptions for two reasons:

 *  The caller violated the precondition of the contract (passing an
    invalid parameter, for instance).  Note that ALL such exceptions
    are supposed to be avoidable, given enough diligence on the caller's

 *  The service was unable to fulfill the contract due to the moral 
    equivalent of force majeure (out of disk space, etc.).  No action the
    caller could possibly take beforehand would obviate the need to catch 
    / propagate these exceptions.

The "EOF" problem in Python acts like one of the second group, because the
file-object-protocol does not supply a test for EOF (callers who can't test for
EOF, can't be blamed for reading off the end).  The tradeoff here is that the
FOP is a "bigger tent" than if it provided EOF():  many FOP-obeying objects
literally can't determine EOF without trying to do the read anyway (sockets,
FIFOs, etc).

Using exceptions for other purposes requires a more definite protocol for them
between caller and service, and thus requires more design justification.   Two
cases I see often:

Because they unwind the stack cleanly, exceptions provide an expedient way to
return "success" from deeply-recursive routines, such as graph searches.  The
justification is along the following lines:  "non-exception implemtations will
spend as much effort and code to handle returning the OOB data in line as they
do performing the search".

In Soft-n-GUI ("fewmet") programming:  given a suitable framework which catches
the exceptions at the outermost layer and displays them to the user, exceptions
drastically simplify event-handling code:  the event handlers check for nasty
bits at the top, and throw if found;  the rest of the code is unencumbered with
the kinds of ugly control flow which would otherwise be required.

> >What bothers me about using exceptions for flow control
> Presumably you're talking about command flow.  Okay, but exceptions do
> nothing BUT affect flow control.  What else can they do?
> >in situations like this is that the effect of an exception
> >handler is *non-local*, whereas what you're trying to
> >catch is really only a local concern.
> Is it?  Are they?  The effects of an exception toss are as local as the
> user of the function want them to be.
> If EOF was truly local, then file.read would always be able to decide what
> to do with it -- print a message, abort(), pop up a window, or whatever
> else it takes.

Here's the rub:  if read() throws on EOF, it promulgates a policy that EOF is a
"back out" condition:  everyone must wrap almost any call to read() in a try
block, even if only to ignore it, or break out of a local loop.  Because read()
doesn't throw (and thereby doesn't enforce policy at the mechanism level),
applications which don't need the policy don't pay for it;  yet it is trivial
(as the original "YAS" poster shows) to layer the policy on top of the
mechanism, if so desired.


Tres Seaver         tseaver at palladion.com    713-523-6582
Palladion Software  http://www.palladion.com

More information about the Python-list mailing list