Live data from Hacker News

Isaacs: try/catch is an anti-pattern

groups.google.com

41–50 of 140 posts

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

#41
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,…

At least in languages like Haskell you can use things like Monads that allow you to write the high level code and do the error routing for you behind the scenes. In C manually writing the error handling is a painful and error prone process.

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

#43
The best part about exceptions (unchecked), is that they allow an exception to automatically bubble upward to the level of code that actually should be responsible for taking action, without having to write a ton of boilerplate code all the way down the call chain.

Even better, when stack traces in exception logs are examined, it's easy to see where in the call chain things are going wrong.

During a database transaction for example, something might go wrong 5 method calls deep, and I should roll back the transaction.

If I'm forced to either use checked exceptions or use if statements to check whether there was success at each level, then that's a lot of repeated boilerplate try/catch/rethrow or if(success) code which unchecked exceptions free me up from having to write.

If all I receive at the transaction level is a failure code, then what do I log, other than "something went wrong?!". With exceptions, all the work is done for me. I just log the exception stack trace and I can easily see what needs to be fixed.

Much of the time, exceptions are useful because they are thrown becuase of something you didn't anticipate happening, as opposed to something you had planned for when writing the code. And when that unanticipated thing does happen, there is nothing more beautiful than an automatically generated stack trace telling you exactly what happened.

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

#44
post #39

I think the best is a little of both ways. For instance in python: x = some_dict['meh'] Will raise if 'meh' doesn't exist. If you believe that 'meh' should be there in your program, it's fine to 'let it raise an exception'. However, if 'meh' could be there, it's better to use an error style such as: x = some_dict.getDefault('meh', 'some-neutral-value') And continue without raising because there's no need to raise as…

You mean collections.defaultdict http://docs.python.org/library/collections.html#collections....

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

#45
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,…

And you know what? In my experience it's not less robust.

So my code hasn't had every possible failure case thought through and explicitly handled in advance. That's good. Firstly some of those errors are so rare they'll almost certainly never occur in my program's lifetime; by not having to handle them explicitly and individually I save time and money. Secondly I can guarantee that, no matter how good I think I am, the program will eventually find a way of crashing I'd not considered; this approach gives me a clean means of handling unforeseen errors as well.

A bad programmer can write bad code in any pattern and with any tools. A bad C programmer using return values can create so many different standards for how to handle errors that you might as well get out the divining rods to read the code. Personally, done right (as with anything) I happen to like try...catch.

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

#46

Isaacs is spot-on, and this is one reason why I love Objective-C. NSException is for programming errors, which should be rare. You can use try/catch, but you almost never do. NSError is for expected application-level errors.

This is exactly what I came here to say. NSException and NSError combined with the fact that you can send messages to nil objects and just get nil objects back lead to much "cleaner" code in my opinion.

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

#47
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,…

> Look at how much rock stable C software we have out there.

Which would be what exactly. The work of Knuth and djb I'll grant you, but the rest?

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

#48
post #44
post #39

I think the best is a little of both ways. For instance in python: x = some_dict['meh'] Will raise if 'meh' doesn't exist. If you believe that 'meh' should be there in your program, it's fine to 'let it raise an exception'. However, if 'meh' could be there, it's better to use an error style such as: x = some_dict.getDefault('meh', 'some-neutral-value') And continue without raising because there's no need to raise as…

You mean collections.defaultdict http://docs.python.org/library/collections.html#collections....

No he doesn't. defaultdict provides a default value for ALL missing values. His approach allows him to target one key in particular, and is a very common python idiom.

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

#49
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,…

In a modern programming environment you can't think about every possible error. In particular, code often migrates into distributed systems where a whole new range of problems can happen.

For instance, a system might have plug-ins that get data from a CSV file, a relational database and a web service. One day somebody comes along and adds a plug-in that gets data from a noSQL database.

Add a new component to the system and you introduce not only new failure modes but new ways failure impacts the "system a s a whole."

The more decisions you make, the more you will make wrong decisions. Exceptions provide a reasonable default behavior that is "decision free" and reasonable ways to upgrade it.

20 year old C software lived in a simpler world; only specialized network utilities like telnet and tcpwrappers would have to face the consequences of a failing DNS lookup or the temporarily failure of a network switch in Toledo.

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

#50
> I much prefer php's json_decode function, since it just returns `null` on invalid input.

A function which has the same result in case of an error as when given valid input (hint: 'null' is a valid json string) is neither good design, nor something I would actually 'prefer'.

Aside of that (and more to the point of the original article), I do believe that exceptions can be very useful the deeper the abstraction of your libraries gets.

If you are 'far down' the stack and you want to ensure that you are in a position where it's safe to proceed and making it very, very clear for the caller that something went wrong, trow() is the perfect tool in order not to be called with a garbage argument on a successive call to a different function (hint: error results tend to get ignored).

And if you are a user of a library, getting nice exceptions can be very handy too - sometimes even wrapping and re- throwing them.

A very good example of real code: In a command line script which processes a lot of text-data to import into a database delegates to various importer classes depending on import line type.

All these importer classes do their thing and whenever they come across an issue, they just throw an ImporterException with all the context that they know about.

The parent script only has to deal with one single case of Exception to produce nice error messages and show everything about the context where they happened.

I can make the importers as complicated as they need to be and I never have to check a single return value (or forget to check it). There is one central place to handle whatever kind of Error that can creep up.

This is very handy.

Granted, in JS/node where each callback cleans out the stack so that a thrown exception can't be handled by whatever caused the callback to be executed later), exceptions are useless and actually harmful because they can mess up the program flow (which assumes callback to be triggered eventually).

But exceptions being useless in one environment doesn't make the useless everywhere.

Post reply on HN