Boost logo

Boost :

From: John Max Skaller (skaller_at_[hidden])
Date: 2001-08-07 18:20:17


David Abrahams wrote:

> > I agree, but my question is 'Why?' Can you give a more
> > abstract explanation?
>
> For one thing, it's usually poorly optimized for things that are likely to
> happen as often as you'll want to break from a loop.

        That's true, but I want to leave optimisation -- as such --
out of it. OTOH, optimisation is directly linked to the ability to
reason about code from its structure, and in that I'm very interested.

> For another, it's a
> whole lot of syntax to use just to reliably get out of a loop.

        Yes. Is this a property of the syntax, or intrinsic
to exception handling?

> > I'm writing a compiler, if I get any kind of error,
> > I print a message and terminate.
>
> That's a reasonable model, but if I were going to do that there would be no
> point in using an exception: I'd just print the message and call exit(1).

        I throw an exception, because sometimes I translate them.
For example, a message

        Cant find symbol <name> in lookup table'

isn't as useful as

        'In line 29, chars 10-29, the name <name> is not defined'

but I don't want to pass all the context (such as the source reference)
into the table lookup algorithm: it would make the algorithm
less 'generic'. So I catch the exception, and translate it,
at the point where I know the reason the lookup is being done
(cause the user wrote that name on line 29, and the compiler
is doing name binding).
 
> Lots of compilers try to fix up the parse tree and continue so you can find
> more errors(including C++ compilers, but C++ syntax makes that job
> notoriously difficult).

        Yes, if I did that, EH might be useful for restarting.
Good point.

> Some systems don't give you subsystem-wide resource recovery, so you need to
> make sure all destructors run, etc., when the subsystem is torn down. For
> those, an exception is a good way to leave the scope in which the subsystem
> was created.

        Agreed. [And a pain for Felix, since it uses a GC,
there's no stack unwinding: its fast, but the 'resource acquisition
by construction/release by destruction' protocol is harder to implement,
but must be supported]
 
> The only arguments I can think of are based on efficiency and syntax. From
> an abstract viewpoint, there's no problem.

        Well, I gave a loose argument based on notions of localisation:
dynamic EH isn't good for local control because its too easy to
forget to catch the right exceptions, and too hard to make
sure that enough kinds exist to provide enough information
to make the choices you need to. The 'dynamism' means that
the distance between the throw point and catch point can
be tiny or huge. Not so a 'break', a function 'return',
or even a goto (it suffers from poor localisation, but
at least the target must be visible in the same or a containing
scope).

> Lots of syntax, and there is a layer of abstraction introduced.

        AH! It is TOO abstract for local, concrete, requirements.

> > There's something I can't lay my fingers on:
> > EH is dynamic, and very 'loose': its very easy to forget
> > to catch some exception you should have caught.
>
> Naw, almost every try ought to come with a catch(...) at the end.

        But then, what do you do with an unknown exception?
Terminate? Might was well let the exception loose!
Someone above might catch it.

        I think you've put your finger on something here:
you _can't_ catch all exceptions in 'middle ware'
because you don't know either the low level or high
level details. You don't know if you "really" wanted that
'Control C' to escape to a higher level, or a 'disk full'
error -- you don't know what Control C is, nor disk full.

        What you want is to catch all exceptions
'of a certain category' and let half the others through
(the other half are lumped together as 'shouldn't have occurred')
But there's no way to do this short of careful detailed
code inspection (and studying the Standard a lot),
and using some kind of 'base' exception for that
category so you can write:

        catch (X) ..
        catch (Y)
        catch (Base) ..

where 'Base' is a base of X and Y.

> Just as easy to avoid checking for a particular error code, no?
>
> > In SML, you can use pattern matching
> > to ensure you catch _all_ the cases,
>
> That's spelled catch(...) in C++.

        No: if you write:

        match x with
        | X -> ...
        | Y -> ...
        | Z -> ...

and you add a case W, then you get a message. You can't forget
UNLESS you add a catch all:

        match x with
        ...
        | _ -> (* like 'default' in C *)

However, exceptions (in Ocaml) are the same as C++:
there's an open ended set of them.
 
> I think you hit the nail on the head. They "seem" to provide static
> guarantees, if you ignore the facts. I think people would be better off
> ignoring what they seem to provide and dealing with the facts.

        Yes, but that's a universal truth :-)
 

-- 
John (Max) Skaller, mailto:skaller_at_[hidden] 
10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850
New generation programming language Felix  http://felix.sourceforge.net
Literate Programming tool Interscript     
http://Interscript.sourceforge.net

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk