Hacker News new | past | comments | ask | show | jobs | submit login

I am not a huge fan of exceptions per se, but it’s important to understand that they are a heuristic for minimizing ‘worry’ about things that are unlikely. I am not saying it’s a good thing, I am saying it’s the way people naturally work.

Let’s say there is a function that’s 20 lines long, and if you did a thorough analysis of possible error conditions, regardless of likelihood, you might come up with 50 or more.

We are not going to write code to address all 50 possibilities from the start. Instead, we are going de facto to wait and see what fails in the real world, and address them as we discover them, because we value our time. We make an economic distinction between a 1-in-1,000 problem, and a 1-in-1,000,000,000 problem.

Is this un-robust? Yes. Are we allowing exceptions to be a control-flow catch-all? Yes. Would a Go-like approach of simply returning error conditions reduce bugs? Probably. But it’s important to recognize programmers’ ‘revealed preference’ for exceptions.




50 error conditions in a 20-line function doesn't really sound even remotely realistic. Probably only 5 of the 20 lines are actually calling functions that might return errors, and in most cases, we don't care what type of error is being returned.

So if we're talking about 5 error-checks in 20 lines, then yes, we absolutely should write code to address them from the start.

I mean, I can understand not dealing with errors from memory allocation failing, or even possibly failure to write bytes to disk, depending on the situation (e.g., if those fail, you've got bigger problems to worry about than your error handling -- and it's not like exceptions are probably helping you to recover anyways).

But for stuff like network communication, writing to databases, etc., you had definitely better be addressing all error possibilities from the start, because these things fail all the time.


Nonsense.

Is the network up?

Is the connection to SQL up?

Did someone just turn off the SQL machine half way through the query?

Can we find the server?

Are there any rows?

Did the SQL compile?

Do I have rights on this table?

Have you just terminated me as a result of a deadlock?

Did you return a Null when I was expecting a value?

Did you return a float when I was expecting an int?

Did my value just overflow?

Did you just return 0 and I tried to use it in division?

Did I just try to access the session but some other idiot clear it?

Did I just try to call a method on an object that is in fact null?

And that's all possible in a three liner off the top of my head. I'm sure there's plenty more than that that are possible! I didn't even start on the file ones...


I totally disagree. These are all the same:

    Is the network up? / Is the connection to SQL up? / Did someone just turn off the SQL machine half way through the query? / Can we find the server?
These are not errors, just normal business logic that has to be handled:

    Are there any rows? / Did you return a Null when I was expecting a value?
These are not runtime errors, they're just debugging during development (with possible exception of overflow, depending on context):

    Did the SQL compile? / Do I have rights on this table? / Did you return a float when I was expecting an int? / Did my value just overflow? / Did you just return 0 and I tried to use it in division?
And likewise, these all just have to do with the design of your program, which you either know you have to deal with or not:

    Have you just terminated me as a result of a deadlock? /  Did I just try to access the session but some other idiot clear it? / Did I just try to call a method on an object that is in fact null?
I already said that you may not have to worry about things like memory allocation errors, depending on your needs. Most of the stuff listed above is either redundant, or has more to do with the design of your program. I stand by my point that, in most programming (say, back-end web stuff), you're handling more like 5 errors per 20 lines, not 50 per 20.

And that, yes, those 5 (or however many) errors should be planned for from the start.


Functions should be scoped appropriately so that they only deal with one thing at a time. A function that checks for network connectivity isn't going to be checking for missing rows. Those are different problems, and should be handled by different functions.

Using your example, we have a function that queries a database. It will be given a valid database connection, and return the result of the query.

There is no "valid database connection" logic, since that is handled elsewhere. There is no result validation logic, since that is handled upstream. This function only cares about A) querying and B) returning a value (possibly null). The only exceptions that is handles is when something specific to it's domain goes wrong - for example, unauthorized access to a table. That is an error that is above networking (the connection worked fine) but clearly not a data validation problem (no data), so we handle the exception here.

If you find yourself throwing exceptions "across problem domains", that's a good indicator that your functions are doing too much.


You can't just assume that a valid database connection will remain valid the entire time you're using it. The network or server is free to go down at any time. In practice, this rarely happens, it's an exceptional condition. Exceptions are the best way to model these kind of errors.


Sure, but the query goes through the layer of functions that actually deals with the database connection. If an error occurs, that layer is responsible and the "higher" layers simply pass on the exception that is thrown.

Point is: the function that deals with database response should never be responsible for dealing with database connection errors.


The Haskell solution is to decompose the problem into the pure and impure parts while using types to eliminate a number of these. Then you end up with general classes of exceptions which can be handled using pure Maybe types, perhaps, in various locations as appropriate.

Resource availability (Is the network up? Is the connection to SQL up? Can we find the server? Did I just try to access the session but some other idiot clear it?)

Incomplete response (Did someone just turn off the SQL machine half way through the query? Have you just terminated me as a result of a deadlock?)

Result semantics and types (Are there any rows? Did you return a Null when I was expecting a value? Did you return a float when I was expecting an int? Did my value just overflow? Did you just return 0 and I tried to use it in division?)

Translation to intermediate language (Did the SQL compile?)

Assumptions about remote state (Do I have rights on this table? Did I just try to call a method on an object that is in fact null?)

Smart code handles these all separately. It's crazy to try to bundle them all into one function.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: