Live data from Hacker News

Exceptions (2003)

joelonsoftware.com

11–20 of 93 posts

Re: Exceptions (2003)

#12
post #7

Some Haskellers treat exceptions as something that you only use if the program has entered an unrecoverable condition and needs to crash.

I don't find this true at all. Haskell exceptions don't look like exceptions in other languages, so it's easy to get hung up on the fact that error is generally used only for unrecoverable errors. But that's why it's called error, not exception. In Haskell, Either and Maybe are used where I would normally use try/except in Python.

The only exception to this that I've found is that error is something you may need to deal with in the IO monad, where in Python it would still be handled via exceptions.

Re: Exceptions (2003)

#13
Sure, exceptions are bad most of the time. But sometimes they are really useful, like in heavily recursive code, i.e. recursive parsers. Catching exceptions in a single top level function and throwing in every other one makes code much cleaner, since you don't have to propagate and handle errors on every function call and you have single exit point on top level function anyway.

Re: Exceptions (2003)

#14
post #9

Earlier quoted context omitted.

His argument is really against using exceptions as part of normal operation, which I agree with. I've noticed when writing plugins to big monolithic programs like 3DS Max and game engines that these tend to throw and catch exceptions as a matter of course, which is a pain when you're trying to debug your own plugin code. An exception should mean "normal operation cannot continue", and should signify a bug in your cod…

I got a question. Do you think it's okay use exceptions to end what would be otherwise an infinite loop? Python example: data = "" socket.settimeout(1.5) while 1: try: data += socket.recv(1024) except Exception,e: store_data(data) break If this is not okay, what would you change? (And yes, I know there are edge'ish cases were I'd miss some data here)

It would be okay as an optimisation in a very hot spot in your code, after a lot of benchmarking. I would frown upon using that as a general practice.

Re: Exceptions (2003)

#15
post #9

Earlier quoted context omitted.

His argument is really against using exceptions as part of normal operation, which I agree with. I've noticed when writing plugins to big monolithic programs like 3DS Max and game engines that these tend to throw and catch exceptions as a matter of course, which is a pain when you're trying to debug your own plugin code. An exception should mean "normal operation cannot continue", and should signify a bug in your cod…

I got a question. Do you think it's okay use exceptions to end what would be otherwise an infinite loop? Python example: data = "" socket.settimeout(1.5) while 1: try: data += socket.recv(1024) except Exception,e: store_data(data) break If this is not okay, what would you change? (And yes, I know there are edge'ish cases were I'd miss some data here)

Exceptions for control flow are a slippery slope. in the socket case, it would be better to parse a terminator frame from your recieved data and just do socket.close() like normal than to hack a timeout or internal socket close, or negociate a fixed transmission length in advance.

This is on the basis code like this is hard to debug, moreso than any glorious exception free master style. You aren't guaranteed to have recieved your entire transmission in your exception block because you are catching any recieve exception. You do want exception handling here, but not as control flow, you want it as damage control if you get an unexpected early termination, not when you get desired behavior.

Re: Exceptions (2003)

#16
post #11
post #7

Some Haskellers treat exceptions as something that you only use if the program has entered an unrecoverable condition and needs to crash.

Isn't that what exceptions are used for in any language?

Certainly not. In Python, for example, exceptions are used to handle exceptional conditions.

Here's an example. Say I'm writing a function and I have a dictionary I need to access values from often. Now say that 85% of the time the key I need is in the dictionary, but 15% of the time it is not. I could do this:

    if key in my_dict:
        execute_operation(my_dict[key])
    else:
        pass
So that if the key is not in the dictionary I do nothing. But this can be expressed more clearly like this:

    try:
        execute_operation(my_dict[key])
    except KeyError:
        pass
This is considered to be clearer because it expresses the fact that the key should be in the dictionary, but in some cases is not. And interestingly, performance reflects this. The first method is more efficient in cases where the key is usually not in the dictionary. The second method, on the other hand, is more efficient when the key is usually present in the dictionary.

So, in summary, exceptions are used in Python to represent cases where successfully executing the code within the try block is normal, but exceptional conditions could once in awhile occur. Almost all uses of exceptions occur for conditions where the program should not crash. When the program should crash we just let the exception bubble up to the top level where we gracefully shut down the program and call an exit function.

Re: Exceptions (2003)

#17
Everyone here seems to agree that "exceptions are for exceptional conditions". The problem is that when you get down to details, there is disagreement about what exactly is an "exceptional condition".

e.g. - you are trying to open a file for reading. The file does not exist. Is this exceptional? That depends on context, but the function that opens the file, being in an independent library, is usually designed without this context.

If it does throw an exception, some people complain that "of course it'e expected that file won't be there sometimes! that's not exceptional".

If it doesn't throw an exception, some people complain that "we tried to open a file, but didn't succeed, of course that's an exception". But if you want to avoid an exception in this case, you'll need to check for existence before opening (LBYL "look-before-you-leap"), and get into a race condition (TOCTOU "time-of-check,time-of-use"), which is really bad.

So it very often happens that you are forced by your ecosystem to use exceptions for normal control flow. Claims that you can only use it for "exceptional / unexpected" tend to be incompatible with a project in which you do not develop/control all of the library you use to your strict standard of exceptionalness.

Re: Exceptions (2003)

#18

Exactly fits the philosophy of Google Go - http://blog.golang.org/error-handling-and-go I think his point of there being easy syntax for multiple returns is critically important to make this sort of error handling non annoying - which Go does remarkably well. I think this factor has a lot to contribute to the fact that you get the warm fuzzy feeling after your code compiles. You feel confident that you have already h…

That was my first thought as well, glad to see that Joel is on the same page.

After writing a fair amount of Go recently, I've come to believe that usage of explicit error returns only appears to increase code density. In reality, it exposes the complexity of correct error handling and forces you to factor your error handling logic accordingly, rather then letting you sweep it all into a few top level handlers.

Re: Exceptions (2003)

#19

Exactly fits the philosophy of Google Go - http://blog.golang.org/error-handling-and-go I think his point of there being easy syntax for multiple returns is critically important to make this sort of error handling non annoying - which Go does remarkably well. I think this factor has a lot to contribute to the fact that you get the warm fuzzy feeling after your code compiles. You feel confident that you have already h…

The name of the language is Go, not "Google Golang"

That said, this was, for me, the single weirdest thing to get used to when starting to program in Go, coming from a mostly Python/Java exception-style background. (I imagine it's easier if you're a C programmer).

However, once I got into the swing of it, I realized I really, really like Go's error handling, and I can't imagine going back to Python's exceptions voluntarily. Returning errors makes code much more readable, and it also reduces the risk of code suddenly failing because of an exception that got thrown somewhere that you can't even find easily.

Go also gets a more subtle point correct: errors are interfaces, not types, which means that you can use any type as an error, as long as it supports the "Error() string" method. This is irrelevant 99% of the time, but I've seen a few pieces of code which utilize this feature very effectively.

Post reply on HN