Discussion:
try blocks (exceptions)...I finally 'get it'..Do you use them often?
chris at seberino.org ()
2010-08-22 12:46:23 UTC
Permalink
I've always been suspicious of using try blocks (exceptions) in my code.

I've even heard they are frowned upon as bad programming practice in some
cases.

I often find other ways to handle errors without using exceptions.

Recently I needed to add more and more code to handle a vulnerable network
operation. I decided to try a try block (exception catching) and was amazed
how much tinier my code was.

If this holds up I'll be very happy. I think I've finally "seen the light"
regarding exceptions.

Anyone else in the same boat?

Chris
Darren New
2010-08-22 16:03:26 UTC
Permalink
Post by chris at seberino.org ()
If this holds up I'll be very happy. I think I've finally "seen the light"
regarding exceptions.
I have never had a problem understanding exceptions and why (or more
precisely when) they're easier to use than error return codes.

The primary benefit is that they *do* close the nested scopes. I.e., that
you don't have to write code at every level to bail out. You can just catch
the exceptions where you're ready to handle them, if you're careful to clean
up properly.

A great number of my programs have basically

=> one try/catch at the top level to log unexpected errors,

=> one try/catch around (say) each transaction (which is what you seem to be
describing),

=> as well as a few tiny ones in places where an error code would make more
sense but that isn't what the library provides (like if the library throws
when failing to open a socket or something). Or where the library throws
instead of doing something sensible (like providing a flag telling you
whether the routine would throw were you to call it - I'm looking at you,
Microsoft).

People who use exceptions instead of error return codes are the ones who
complain that exceptions are uglier. People who use them the same way you'd
use setjump/longjump are the ones who understand the stuff.

If you really want an excellent book about this sort of stuff, try
http://www.amazon.com/Object-Oriented-Software-Construction-Book-CD-ROM/dp/0136291554
It talks about Eiffel, not like "here's Eiffel" but more like "here's the
theory behind why OOP and OOD works the way it does, and oh look, here's a
language designed to do that." He basically justifies every feature of the
language in a mathematical-like way, except for the two or three features
where he says "Yeah, well, you really need to allow this to make it work
easily." You may not agree with all of his decisions or the design of his
language, but he makes some excellent points. (Much like you might think
Ada is too oppressive even as you acknowledge that it makes for fewer
bugs/mistakes getting deployed.)

I bring this up, because one of his decisions is that you can't catch an
exception and pick up from where you left off - that ability indicates bad
design, in the same way that resuming a database transaction that failed
without first rolling back the changes is a bad idea.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
chris at seberino.org ()
2010-08-22 17:50:30 UTC
Permalink
Post by Darren New
I have never had a problem understanding exceptions and why (or more
precisely when) they're easier to use than error return codes.
They are amazingly powerful. As an example, think of all the reasons a socket
function could go bad....

1. You networking is down.
2. Remote node is down.
3. Remode node is up but intermittent due to a DDOS attack.
4. Your networking is up but intermittent due to wife in next room streaming video
from YouTube.

With exceptions you can basically say "I don't care what goes wrong....Just
keep retrying until successful." That little try block will catch EVERYTHING!
That is handly.
Post by Darren New
=> one try/catch at the top level to log unexpected errors,
I don't understand this. Are you you saying your ENTIRE program is inside one
big try block?
Post by Darren New
=> one try/catch around (say) each transaction (which is what you seem to
be describing),
If you haven't enough of these then your top level try block is superfluous
right?
Post by Darren New
People who use exceptions instead of error return codes are the ones who
complain that exceptions are uglier. People who use them the same way
you'd use setjump/longjump are the ones who understand the stuff.
I'm not familiar with setjump/longjmp so I missed that point.
Post by Darren New
I bring this up, because one of his decisions is that you can't catch an
exception and pick up from where you left off - that ability indicates
bad design, in the same way that resuming a database transaction that
failed without first rolling back the changes is a bad idea.
So he's saying you HAVE to restore state to before the exception? I'm not sure
how he'd enforce that. Would he be ok with my socket example above? There you
are retrying the socket connection so I suppose that counts as restoring back
to your original state no?

cs
Darren New
2010-08-22 18:40:40 UTC
Permalink
Post by chris at seberino.org ()
With exceptions you can basically say "I don't care what goes wrong....Just
keep retrying until successful." That little try block will catch EVERYTHING!
That is handly.
Yes, exactly. I've worked with libraries where *opening* the socket throws
an exception if it can't connect, tho. That's just silly.
Post by chris at seberino.org ()
Post by Darren New
=> one try/catch at the top level to log unexpected errors,
I don't understand this. Are you you saying your ENTIRE program is inside one
big try block?
For server programs? Sure. Some unexpected error happens that you haven't
already caught, you catch the exception, log the error, and then either bail
out or clean everything up, depending.

If it's a video game, say, you put the main game loop inside an exception
catch, then display the traceback when it fails, with the hope that it'll
help you debug during beta test.
Post by chris at seberino.org ()
Post by Darren New
=> one try/catch around (say) each transaction (which is what you seem to
be describing),
If you haven't enough of these then your top level try block is superfluous
right?
Not always, but sure, it ought to be. Depends how big your transactions are,
and how much you do during initialization, termination, and between
transactions. Not everything happens inside a 'transaction' either.

But mainly it's for logging purposes and such.
Post by chris at seberino.org ()
Post by Darren New
People who use exceptions instead of error return codes are the ones who
complain that exceptions are uglier. People who use them the same way
you'd use setjump/longjump are the ones who understand the stuff.
I'm not familiar with setjump/longjmp so I missed that point.
setjump is a label, longjump is a goto, basically, except it can "goto"
anywhere in the code.
Post by chris at seberino.org ()
Post by Darren New
I bring this up, because one of his decisions is that you can't catch an
exception and pick up from where you left off - that ability indicates
bad design, in the same way that resuming a database transaction that
failed without first rolling back the changes is a bad idea.
So he's saying you HAVE to restore state to before the exception?
In this case, each function has an optional "rescue" block. If there's no
rescue block, the exception propagates. If the "rescue" block doesn't end in
"retry" then the rescue block runs and then propagates the exception
(basically, catch followed by rethrow, or finally if you would). If the
block ends in "retry", then it basically branches back to the start of the
function. There's no way to execute the line *after* the line that caused
the exception without starting the whole function over from scratch.

So, yes, exactly your example, with retry. Without the retry, you just get
to fix your invariants before returning.
Post by chris at seberino.org ()
I'm not sure how he'd enforce that.
Well, that's what the rest of the language is about. It's all kind of
interrelated. If you don't actually put in code what "restore state" means,
then there's no way to enforce it. But he does have code structures that
indicate what it means to "restore state", so that's OK.
Post by chris at seberino.org ()
Would he be ok with my socket example above? There you
are retrying the socket connection so I suppose that counts as restoring back
to your original state no?
It's a whole tome of a book. It's available online free from some places,
altho I can't say for sure how it got there. (Actually, IIRC, when you buy
the development environment it comes with a PDF copy of the book, so it's
probably at least semi copyright violation.) But the actual text is
worthwhile, even if you never use the language, just to see how you can sit
down and logically design something like that.

But to answer the question, you have to throw an exception if you can't meet
your postconditions, and even if you throw an exception you still have to
fix your invariants. Look up "design by contract" for an idea of what all
that means.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
chris at seberino.org ()
2010-08-22 19:04:04 UTC
Permalink
Post by Darren New
Post by chris at seberino.org ()
I don't understand this. Are you you saying your ENTIRE program is inside one
big try block?
For server programs? Sure. Some unexpected error happens that you haven't
already caught, you catch the exception, log the error, and then either
bail out or clean everything up, depending.
I've noticed that the web frameworks I've worked with, Django and TurboGears,
log errors and never really "crash". So it appears they are putting all user
generated code into a mega-try block for me.

Chris
Chris Rebert
2010-08-23 05:24:46 UTC
Permalink
Post by chris at seberino.org ()
With exceptions you can basically say "I don't care what goes
wrong....Just
keep retrying until successful." ?That little try block will catch
EVERYTHING!
That is handly.
Yes, exactly. ?I've worked with libraries where *opening* the socket throws
an exception if it can't connect, tho. That's just silly.
Why?

Cheers,
Chris
Darren New
2010-08-23 11:30:45 UTC
Permalink
Post by Darren New
Post by chris at seberino.org ()
With exceptions you can basically say "I don't care what goes wrong....Just
keep retrying until successful." That little try block will catch EVERYTHING!
That is handly.
Yes, exactly. I've worked with libraries where *opening* the socket throws
an exception if it can't connect, tho. That's just silly.
Why?
Because failing to open a socket is no more an exceptional condition where
you'd want to unwind a bunch of processing than failing to open a file is.
The overhead of throwing an exception for that case is too high
(syntactically and performance-wise) for a relatively common condition.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
Darren New
2010-08-23 12:40:37 UTC
Permalink
Post by chris at seberino.org ()
Would he be ok with my socket example above?
By the way, the answer here would be "no", I think. Thinking on it,
exceptions in Eiffel are really for errors that you can't give an error code
for, more than anything.

The principle of "command/query separation" says that each routine either
modifies state or returns a value. I.e., "functions" don't modify state, and
"procedures" don't return values. So to open or read a socket, you invoke
mysocket.open(....)
then
if !mysocket.is_open then print mysocket.failure_reason
so there's no need for exceptions.

The problem Joel talks about with having out parameters and a return value
telling you whether it worked is a problem of Joel not knowing how to do OO
programming. He's using one "routine" that's neither a function nor a
procedure, instead of making two methods of one object to do the work.

I saw an article saying how great the API for pthreads was, just in terms of
general design, etc etc, even if it wasn't a great threading library per se.
Except it was basically faux-OO on top of C, with command/query separation.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
Gus Wirth
2010-08-23 16:05:45 UTC
Permalink
Post by chris at seberino.org ()
Post by Darren New
I have never had a problem understanding exceptions and why (or more
precisely when) they're easier to use than error return codes.
They are amazingly powerful. As an example, think of all the reasons a socket
function could go bad....
1. You networking is down.
2. Remote node is down.
3. Remode node is up but intermittent due to a DDOS attack.
4. Your networking is up but intermittent due to wife in next room streaming video
from YouTube.
With exceptions you can basically say "I don't care what goes wrong....Just
keep retrying until successful." That little try block will catch EVERYTHING!
That is handly.
[snip]

It might not. Or more specifically, you should be careful to only catch
the most precise level of exception necessary for the immediate problem.

In most object-oriented languages that handle exceptions, the exception
itself is an object that inherits from some ancestor exception. So the
crude approach might be to capture all network failures and treat them
in the same manner, while the more sophisticated approach would
distinguish between the failure modes and give the application some
additional options in how to handle the failure.

In your example, having the network interface down might be handled
differently than having the remote node being unreachable, perhaps
producing an error message saying "please check you network card
connection" vs "I can't reach the remote computer". And being unable to
reach the remote computer might be a matter of the connection being
refused rather than being actually unreachable.

These would all be cases where you can use sub-classing of the network
exception object to get finer resolution on what the problem is and how
you want to handle it. Of course, if all you want to do is retry no
matter what, then feel free to just use the generic network failure
exception.

Gus
Chris Rebert
2010-08-23 05:36:32 UTC
Permalink
Post by chris at seberino.org ()
I've always been suspicious of using try blocks (exceptions) in my code.
I've even heard they are frowned upon as bad programming practice in some
cases.
Most infamously by Joel Spolsky:
http://www.joelonsoftware.com/items/2003/10/13.html

His blog post provoked several good rebuttals, easily googled for.

Cheers,
Chris
Darren New
2010-08-23 11:33:03 UTC
Permalink
Post by Chris Rebert
Post by chris at seberino.org ()
I've always been suspicious of using try blocks (exceptions) in my code.
I've even heard they are frowned upon as bad programming practice in some
cases.
http://www.joelonsoftware.com/items/2003/10/13.html
His blog post provoked several good rebuttals, easily googled for.
And his basic complaint is that he tries to resume processing from the point
of the exception. That's not what they're for.

I bet he uses return, break, and continue, tho.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
chris at seberino.org ()
2010-08-23 12:11:38 UTC
Permalink
Post by Darren New
And his basic complaint is that he tries to resume processing from the
point of the exception. That's not what they're for.
The main thing exceptions seems VITAL for is cases where you just don't know
everything that can go wrong. How else could you code up fragile precarious
operations WITHOUT exceptions?

Without exceptions you'd be forced to try to detect all error cases and react
appropriately. But my point above is that some operations can't have all
failure modes anticipated!

cs
Darren New
2010-08-23 12:29:42 UTC
Permalink
Post by chris at seberino.org ()
The main thing exceptions seems VITAL for is cases where you just don't know
everything that can go wrong. How else could you code up fragile precarious
operations WITHOUT exceptions?
Well, technically, someone *does* know everything that can go wrong. Someone
somewhere is throwing the exception. It might not be *you*, and it might not
be documented, but certainly the socket library and/or kernel knows what's
going wrong.

Now, if there's a programming bug that causes a problem, then yes, an
exception is useful. Without that, and requiring every operation that might
fail to have an error return, you wind up with things like C and C++, where
programming bugs become undetectable and undebugable. There's no return
value from { thing->data[4]; } that will tell you that 'thing' is null or
that data only has two elements.

Exceptions are handy even when you know what can be thrown, because they
stop the evaluation before the bad value is used.

I think the people who complain about exceptions being non-local are the
people who either try to use them instead of error codes when error codes
make more sense, or people who are using a language where cleaning up after
exceptions are thrown is painful to get right.
Post by chris at seberino.org ()
Without exceptions you'd be forced to try to detect all error cases and react
appropriately. But my point above is that some operations can't have all
failure modes anticipated!
I disagree. There can be many causes for (say) a socket operation to fail,
but you can most definitely detect them all. You might not be able to tell
if it's the remote host getting unplugged or the router getting unplugged,
but exceptions won't tell you that either.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
chris at seberino.org ()
2010-08-23 12:50:19 UTC
Permalink
Post by Darren New
Post by chris at seberino.org ()
Without exceptions you'd be forced to try to detect all error cases and react
appropriately. But my point above is that some operations can't have all
failure modes anticipated!
I disagree. There can be many causes for (say) a socket operation to
fail, but you can most definitely detect them all. You might not be able
to tell if it's the remote host getting unplugged or the router getting
unplugged, but exceptions won't tell you that either.
(BTW I appreciate all your good comments.)
How do you know you can detect all failure modes? My Firefox loads pages 99%
of the time but once in a blue moon I need to reload for some mysterious
reason. Don't you experience that too?

In networking a lot is out of your control which makes the developer look bad
when things go wrong that aren't his fault.

It now seems to me that networking code without exceptions is like driving down
the freeway without seat belts.....You'll probably be ok...maybe even for
years...but you never know.....

cs
Darren New
2010-08-23 16:06:58 UTC
Permalink
Post by chris at seberino.org ()
(BTW I appreciate all your good comments.)
How do you know you can detect all failure modes?
If you can't detect them, it isn't a failure.
Post by chris at seberino.org ()
My Firefox loads pages 99%
of the time but once in a blue moon I need to reload for some mysterious
reason. Don't you experience that too?
That doesn't mean firefox didn't detect the failure. It just means it didn't
bother you with the failure.

Note that "failure to meet the requirements of an RFC" are quite different
from "failure of code to do what it was written to do." If you ask for a
text file via HTTP and there's no content-length header on the return,
there's no way for the code to know the server didn't send the entire text file.
Post by chris at seberino.org ()
In networking a lot is out of your control which makes the developer look bad
when things go wrong that aren't his fault.
True. But that doesn't mean you can detect the failure, either.

Distinguish between "something failed" and "something in my code detected a
failure."

Exceptions don't detect failures. They just prevent you from ignoring them.
*Something* has to throw the exception. If you can check for errors at every
place an exception could be thrown, then you could write code just as robust
with error checking as you can with exceptions.

I.e., every single C syscall into UNIX returns error codes. Nothing prevents
you from reliably detecting errors, including those you have no way of
fixing (like a failure on close()). Every attempt to open or read or write a
socket will tell you if the socket got disconnected. There's nothing magical
about exceptions except in the way they unwind the stack.
Post by chris at seberino.org ()
It now seems to me that networking code without exceptions is like driving down
the freeway without seat belts.....You'll probably be ok...maybe even for
years...but you never know.....
Nah. You just have to be careful to check the return codes.

What I'm saying is that Linux (AFAIK) doesn't have exceptions. The closest
it comes is signals. When you see some language or library throwing
exceptions because you couldn't write to a socket, it's because inside the
library it said something like

int x = write(socket, buf, count);
if (x < 0) throw Exception("Socket write failed!");

You can do that yourself.


In Eiffel, opening or writing or reading a socket would be a procedure that
doesn't return any value at all. After you've done the procedure, there will
be another status function that does nothing but return whether it worked or
not. The only time you'll get an exception is if you make a programming
mistake, such as trying to read or write a socket that either isn't open or
isn't in a non-error state. I.e., the precondition on "socket.write" would
be "socket.is_open && socket.error_code == 0" or some such.


Hermes does it a completely different way, but that language is so unlike
anything else I've seen procedural that even trying to use the same
terminology is just going to confuse people.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
chris at seberino.org ()
2010-08-23 16:28:33 UTC
Permalink
Post by Darren New
int x = write(socket, buf, count);
if (x < 0) throw Exception("Socket write failed!");
You can do that yourself.
I'm using a testing framework called Selenium. Ever heard of it? It tests
your web apps by simulating what clients would do. I don't think the Python
Selenium libraries have return codes. When things go wrong it just throws an
exception.

I see your point....if Selenium had error codes I could just as easily read
those values.

Chris
Darren New
2010-08-23 16:32:18 UTC
Permalink
Post by chris at seberino.org ()
Post by Darren New
int x = write(socket, buf, count);
if (x < 0) throw Exception("Socket write failed!");
You can do that yourself.
I'm using a testing framework called Selenium. Ever heard of it? It tests
your web apps by simulating what clients would do. I don't think the Python
Selenium libraries have return codes. When things go wrong it just throws an
exception.
I understand that python (for whatever reason) generally uses exceptions for
*every* kind of failure, even those where it can be expected to be rather
common.
Post by chris at seberino.org ()
I see your point....if Selenium had error codes I could just as easily read
those values.
Yup. The difference is in the control flow, not in the error reporting itself.
--
Darren New, San Diego CA, USA (PST)
Quoth the raven:
Need S'Mores!
Olli Hollmen
2010-09-02 15:36:54 UTC
Permalink
Hi all exception throwers !

"setjump is a label, longjump is a goto, basically, except it can
"goto" anywhere in the code."
is a really good overall description what setjmp / longjmp mechanism
does to implement exceptions in C.

To see even more light on this useful exception mechanism see "man
setjmp" and "man longjmp" on UNIX / Linux or google for these if you
are a windows user (also http://en.wikipedia.org/wiki/Setjmp.h).
Reading some of the above is very enlightening for understanding how
languages with built-in try / throw / catch
work on the lower level and how compilers have work the whole thing out.

The setjmp and longjmp are also well explained in Advanced Programming
in the UNIX Environment, Addison-Wesley, 1992. by W. Richard Stevens

While ago I just retrofitted setjmp / longjmp exception throwing into
my web application framework where the callbacks can now use wrapper
webreq_throw(req, msg) to leave a descriptive message to request
object established on the top level where exception is handled and
error is reported (webreq_throw() obviously calls the longjmp).

Of course setjmp / longjmp is rather rudimentary and tedious
mechanism compared to try / throw / catch, but
its great it's available for c programmer.

With best regards

Olli
Post by Darren New
Post by Darren New
int x = write(socket, buf, count);
if (x < 0) throw Exception("Socket write failed!");
You can do that yourself.
I'm using a testing framework called Selenium. ?Ever heard of it? ?It
tests
your web apps by simulating what clients would do. ?I don't think the
Python
Selenium libraries have return codes. ?When things go wrong it just throws
an
exception.
I understand that python (for whatever reason) generally uses exceptions for
*every* kind of failure, even those where it can be expected to be rather
common.
I see your point....if Selenium had error codes I could just as easily read
those values.
Yup. ?The difference is in the control flow, not in the error reporting
itself.
--
Darren New, San Diego CA, USA (PST)
? ? ? Need S'Mores!
--
http://www.kernel-panic.org/cgi-bin/mailman/listinfo/kplug-lpsg
Tracy Reed
2010-08-23 15:56:47 UTC
Permalink
Post by Darren New
And his basic complaint is that he tries to resume processing from
the point of the exception. That's not what they're for.
I bet he uses return, break, and continue, tho.
He is a big fan of functional programming and continuations. I bet
that has some bearing on his view of exceptions.
--
Tracy Reed
http://tracyreed.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.kernel-panic.org/pipermail/kplug-lpsg/attachments/20100823/d18e8d78/attachment.pgp
Loading...