Live data from Hacker News

Isaacs: try/catch is an anti-pattern

groups.google.com

71–80 of 140 posts

Re: Isaacs: try/catch is an anti-pattern

#71
post #33

Earlier quoted context omitted.

This is a bad idea that keeps coming back again and again. I see nothing wrong with exceptions, I do have a problem with (1) checked exceptions, and (2) catching exceptions prematurely and (3) people not learning how to use "finally" so they do (2) and rethrow. Languages like Go and Scala roll out various mechanisms that bring us back to the bad old days of C, when we had to check the return/value and or the error co…

> when we had to check the return/value and or the error code after every function call... if we wanted error handling to work. Errors as return values force you to think about every possible error, which is a good thing for code quality. Look at how much rock stable C software we have out there. Software that can be compiled on many different architectures, run in many different environments, and it all just works,…

I'm sorry, but this is a very bad example. iptables had an issue for a long time where error code is not carefully preserved in many situations and you end up with messages like:

    iptables: Unknown error 4294967295
This wouldn't happen with exceptions - even if not handled properly, you'd see where is it originating and what's the most probable cause of the issue. And it's not necessarily iptable's fault - in some cases you have to really bend some rules to get the error you want. Also you cannot stack them so if you fail to cleanup after the original error, what do you return? The first or the second error? One has to be ignored.

Re: Isaacs: try/catch is an anti-pattern

#72
post #9

This seems to be exactly the attitude of Go: "We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional. Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloa…

This is a bad idea that keeps coming back again and again. I see nothing wrong with exceptions, I do have a problem with (1) checked exceptions, and (2) catching exceptions prematurely and (3) people not learning how to use "finally" so they do (2) and rethrow. Languages like Go and Scala roll out various mechanisms that bring us back to the bad old days of C, when we had to check the return/value and or the error co…

when you're building real systems, the complexity of the error handling can approach or exceed the complexity of the "normal" path and when that happens you're in deep trouble.

Go is a systems programming language, and a large part of systems programming is dealing with the potential errors. Take a look at, say, how the Linux kernel implements a system call. In fact, this is do_mmap_pgoff(), which does the bulk of the work for a mmap() system call in Linux: http://lxr.linux.no/linux+v3.1.1/mm/mmap.c#L942

It's almost nothing but error checking, and I submit that is as intended. In this circumstance, you want all of the error checking right in front of you, because that error checking is enforcing very important kernel policy. A lot of kernel code is error checking, because it has a lot of policy to enforce.

You're right that this error checking paradigm is a throwback to C, but Go was designed as a better C. Go's means of handling errors is exactly what I wish I could do in C; it allows every function to both return a value and an error code. It avoids passing in pointer to values because the function returns an error code, or having to check a global errno because the function returns a meaningful value. It's kinda like living in a world where C++, Java and Objective-C were never invented. (I like and use C++, so please don't take that as jumping on the C++-is-the-worst-thing-ever bandwagon.) I find that a very interesting direction, one which should be explored.

I use exceptions for higher-level code. When writing, say, a parser, I'd rather throw and catch exceptions. I don't think we need to choose one error-catching paradigm and declare it's best for all levels of code.

Re: Isaacs: try/catch is an anti-pattern

#73
The way I see it exceptions are helpful in creating self documenting code if used thoughtfully and effectively.*

Some might argue subclassing the base exception to create more specifically named ones is a bit silly, because you may be doing little more than renaming a class several, maybe many, times. But it may be countered that this is simpler than determining a list of error codes and then leaving it to other people to find out what a random string or integer even means. I personally haven't found this helpful for debugging.

Both ways are better than something just returning false and leaving you to figure out why it did that in the first place.

The main benefit to me, however, is to be able to throw the exceptions deeper in the code (where appropriate) and to be able to then catch them at the very last moment. While not perfect (I can't account for everything), it allows me to keep my error handling code cleanly separated from the rest of it at the most abstracted point. Anything lower level will by necessity be a little messier.

eg. not wrapping an entire* script in one try/catch block.

Re: Isaacs: try/catch is an anti-pattern

#74
post #26
post #18

Earlier quoted context omitted.

> It was a little rushed with the whole concept of forcing everyone to handle all exceptions Just to clarify, Java doesn't force you to handle all exceptions (maybe it did at one point in time?). Exceptions which inherit from RuntimeException are unchecked and you can choose whether to handle them or not. Exceptions which don't inherit from RuntimeException are checked

That being said, I'd like to quote these passages from the official Java tutorial: "Generally speaking, do not throw a RuntimeException or create a subclass of RuntimeException simply because you don't want to be bothered with specifying the exceptions your methods can throw. Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client…

> you don't need to neccessarily handle exceptions even if they are checked (in cases where it doesn't make sense that your code handles them). Add a 'throws' clause and let the calling code handle them.

The problem with this is it affects the signature of all methods in your call hierarchy up to the point where it's handled as you're forced to declare that you throw exceptions. A simple change in one class could quickly become a breaking change involving several classes just because an exception can now occur.

Re: Isaacs: try/catch is an anti-pattern

#75

This part really sunk in for me in Bruno Jouhier's reply: > "So the big mistake I've always seen people make is being too "nervous" about exceptions and feeling that they have to do something about them as close as possible to the point where the exceptions were raised. They need to the exact opposite: feel relaxed about exceptions and let them bubble up." Hadn't really thought about it in that way, but I find myself…

> "So the big mistake I've always seen people make is being too "nervous" about exceptions and feeling that they have to do something about them as close as possible to the point where the exceptions were raised. They need to the exact opposite: feel relaxed about exceptions and let them bubble up." While the principle seems to make sense, I find it unusable with GUI like apps. GUI have hundreds of entry point from v…

>Every beautifully written code I've seen has always been CLI programs.

I might be a fairly novice coder, but I think a good solution for this would be a client/server model. I'm a full-time Linux user and for various reasons, I really like application which have a daemon mode, with the UI built as a client accessing said daemon. Good examples are mpd or deluge.

This way, the actual code can handle handle most, if not all exceptions and errors at the "CLI level" and expose meaningful error codes to the "API" that the UI uses. At least that's how I'm trying to build my first bigger software project (an image viewer).

Again, I'm a fairly inexperienced programmer, so this might be a foolish suggestion, but I try to give much thought to the way I'm building software. Maybe even too much, I'm kinda prone to over-engineering.

Re: Isaacs: try/catch is an anti-pattern

#76

Earlier quoted context omitted.

I think the point is that your specific cases: > Many programmers in many situations would be perfectly happy to catch "failure to open a file" and "failure to open a database connection" and "failure to connect to a network host" with one simple handler that logs the failure and either aborts, retries or ignores. aren't exception appropriate a according to a certain portion of developers. The reason they aren't exce…

As far as I can tell either your point is a circular argument or it's an English-language nomenclature complaint fixable by s/exception/fooglewoo/. Either way it doesn't address the real argument, about where it is appropriate to use try and catch. What is inherently better about multiple return values at every level, compared to semi-centralized catch blocks?

I'm sorry, I can't really parse your argument.

My point was that there is a school of htought that exceptions should only be used in "exceptional" circumstances.

The examples given were not exceptional in that a programmer should expect those types of errors during the normal execution of their program. Therefor exceptions aren't the solution to those types of errors.

Does that make more sense to you?

Re: Isaacs: try/catch is an anti-pattern

#77
post #55

An interesting read. It's always nice to see people stating their unpopular opinions with proper reasoning. The author's point of view seems to be pretty Javascript/Node.js -centric. I can relate. try/catch and node.js -style asynchronous coding do not work together. However, I'd say that it's the async programming model that is broken, not try/catch. Writing code in node.js async style is very difficult for humans t…

>> However, I'd say that it's the async programming model that is broken, not try/catch.

This is an interesting point of view, however I'm inclined to disagree on the basis that the async model is representative of how things actually happen; the imperative model is not.

In an asynchronous architecture, the developer is concerned with only the current state and the set of all events that may cause a transition from that state. Whether or not an event is the result of an error condition is irrelevant, one simply invokes a different handler.

I used to consider the asynchronous model much harder to program in, that is until I changed my thought process to work in terms of state machines. Then it actually became much simpler to program in this model since, at the handler level, one has no preconception about what should happen next, only what can happen next and how to handle each of those situations.

>> C++ is pretty nice when it comes to error handling and exceptions as resources are cleaned up on error.

There has been many a discussion about the benefits vs. pitfalls of C++ exceptions. I personally am not a fan since the lack of garbage collection means that there are situations that require lots of tedious and error prone boilerplate code just to ensure that all resources are cleaned up.

I have to admit that perhaps the nicest way I have seen of handling failure is in the concept of Monads in Haskell (and other functional languages). The ability to add the context of failure as a possibility in any computation, without requiring that computation to explicitly consider it is extremely elegant. Add to that the safety of always returning a well defined value that is fully type checked by the compiler and I believe you have a recipe for very effective error handling.

Re: Isaacs: try/catch is an anti-pattern

#78

Earlier quoted context omitted.

As far as I can tell either your point is a circular argument or it's an English-language nomenclature complaint fixable by s/exception/fooglewoo/. Either way it doesn't address the real argument, about where it is appropriate to use try and catch. What is inherently better about multiple return values at every level, compared to semi-centralized catch blocks?

I'm sorry, I can't really parse your argument. My point was that there is a school of htought that exceptions should only be used in "exceptional" circumstances. The examples given were not exceptional in that a programmer should expect those types of errors during the normal execution of their program. Therefor exceptions aren't the solution to those types of errors. Does that make more sense to you?

But using that school of thought to support that school of thought isn't an argument, it's a circle.

PaulHoule is explaining why he likes a specific mechanism compared to another, and you are only replying with the previously-established fact that there exists a disagreement here, not a counterargument.

Re: Isaacs: try/catch is an anti-pattern

#79
I think a good rule is that if you're not planning (or able) to confidently deal with an exception and put the app into a known state, then don't catch it.

Some developers seem to have a fear of allowing any errors to be seen by the user and so they have a habit of swallowing exceptions. I guess it makes them feel that the code is more stable, but it actually masks bugs and makes them impossible to troubleshoot. I have a name for these - I call them "insidious bugs" especially when they result in data loss, which is common with those types of bugs.

I was just in some code the other day that was littered with a bunch of these:

try { ... code here ... } catch(e) {}

not even a console statement or anything! It took two of us over 6 hours chasing down what should have been a 15 minute bug due to that code.

Re: Isaacs: try/catch is an anti-pattern

#80
post #72

Earlier quoted context omitted.

This is a bad idea that keeps coming back again and again. I see nothing wrong with exceptions, I do have a problem with (1) checked exceptions, and (2) catching exceptions prematurely and (3) people not learning how to use "finally" so they do (2) and rethrow. Languages like Go and Scala roll out various mechanisms that bring us back to the bad old days of C, when we had to check the return/value and or the error co…

when you're building real systems, the complexity of the error handling can approach or exceed the complexity of the "normal" path and when that happens you're in deep trouble. Go is a systems programming language, and a large part of systems programming is dealing with the potential errors. Take a look at, say, how the Linux kernel implements a system call. In fact, this is do_mmap_pgoff(), which does the bulk of th…

When writing, say, a parser, I'd rather throw and catch exceptions.

Which is also possible in Go, and template parser from its standard library is, actually, written in this style:

http://golang.org/src/pkg/template/parse/parse.go#L96

Functions call panic() (via t.errorf) to avoid passing errors between multiple levels of functions, but then Parse method catches it with recover(), checks what kind of error it is, and either panics again if it's a runtime error, or returns other kinds of errors.

Post reply on HN