Live data from Hacker News

Isaacs: try/catch is an anti-pattern

groups.google.com

101–110 of 140 posts

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

#101
post #96

I think a lot of programmers use try/catch when what they really want is Prolog-style failure: my_parser(String, Output) :- parseJSON(String, JSON), extract_the_values_I_want(JSON, Output). if my_parser(String, Output) then ...do stuff with Output... else ...show user "couldn't parse" message... I've been using Mercury (a strongly typed Prolog) for years now and have never once found the need for exceptions (which Me…

What are your motivations for using Mercury? Are you using it for hobby projects, research/academic purposes or actual production code?

Hobby projects and hobby research. It has some pretty intense features if you're into type theory.

IMO the library support isn't yet there for production code (e.g. no or only rudimental GUI/networking code). But if you're just using it for computation (e.g. AI or compiling or some such) it's pretty solid, and its FFI is the most straightforward I've ever seen.

FWIW I hear that these people: http://www.missioncriticalit.com/ and these people: http://www.princexml.com/ use it for production code, but I don't know much about them, beyond that Håkom Wium Lie (of CSS and Opera fame) is the Director of the latter.

I maintain a blog about Mercury's features for interested users: http://adventuresinmercury.blogspot.com/ if you're interested.

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

#102
post #8

Anybody who wants to judge try/catch should first go and read about Common Lisp's condition system. See for example the chapter about conditions and restarts from the excellent book "Practical Common Lisp" by Peter Seibel: http://www.gigamonkeys.com/book/beyond-exception-handling-co... Notice I'm not saying you should go and program in Common Lisp, just that you should understand those ideas before you engage in any…

Inspired by Lisp's condition system I wrote a ruby library which comes pretty close to Lisp's error handling. It also implements "restarts" ... a little bit messy though since, as you said, low-level execption are used to get it working. In one point the condition system bootstraps itself which is quite interesting to think about. https://github.com/melkon/conditions An example ("parse_log_file" and "log_analyzer sho…

Have you considered using Ruby's throw/catch instead of exceptions? I did that for Atomy's condition system[1]. They worked great because you can just use the restart names for the throw/catch tags.

[1]: https://github.com/vito/atomy/blob/master/kernel/condition.a...

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

#103
post #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 t…

>> "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."

You're absolutely correct in that many operations are executed asynchronously. However, I think that it shouldn't be the model we use to write programs. Programming is all about abstractions and the imperative model is a good abstraction which can be implemented effectively by a compiler and a runtime system.

Sure, a program can be composed by maintaining a state, which changes when events occur. I just feel that it gets really hairy really quickly when you start to have several IO operations in sequence and have to start thinking about multiple error conditions. With exceptions and imperative code, you can write the IO operations one after another and catch the exceptions where they can be handled (e.g. show an error dialog in the GUI). With hand-written CPS async code you have to assign an error handler to each IO call, even if you'd want to have only one handler for several error conditions.

>> "I have to admit that perhaps the nicest way I have seen of handling failure is in the concept of Monads in Haskell"

I think that failures are not handled with the monad failure function any more in Haskell, but exceptions are use these days (a quite recent addition to Haskell language). A catch can only be in IO code but throw can be in either monadic or functional code.

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

#104
post #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 yo…

I thought a JSON document had to have either a top level object or array, which would make a bare null an invalid JSON text. Granted, we might not be that strict all the time. See section 2, paragraph 2: http://www.ietf.org/rfc/rfc4627.txt?number=4627

[deleted]

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

#105
post #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 t…

> 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.

The problem is memory isn't the only resource that needs to get cleaned up, and at least in Java, when a variable falls out of scope resources such as database connections, opened files, etc, will not instantly be cleaned up.

However, with c++, as long as you're using RAII (and if you're not, why aren't you?), all a resource has to do is fall out of scope to clean it up. RAII is certainly cleaner and less tedious than anything I've seen in Java and C#.

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

#106
post #24

> You can't reasonably argue that this: try { foo = JSON.parse(input) } catch (er) { return "invalid data" } is more lightweight than: foo = JSON.parse(input) if (!foo) return "invalid data This is like saying that walking is faster then driving because I can walk 5 meters faster then it takes me to get into a car. Yes, error codes are more compact in a tiny "Hello world" example because it is only showing one functi…

> Don't throw exceptions if you can handle the error and continue where you left off. Exceptions is for when you can't continue. Yes, although quoting that example doesn't support the assertion. JSON.parse is a library function. How can it judge whether the caller can continue or not just because the JSON cannot be parsed? > Think of throwing as a way to roll back transaction, stop whatever you were trying to do, and…

> JSON.parse is a library function. How can it judge whether the caller can continue or not just because the JSON cannot be parsed?

Don't make assumptions about the caller, throw if your library can't continue.

> So although try/catch avoids the hassle of checking state after each operation, you pay for it on errors.

If your language supports RAII (http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initial...) you get a free ride. Otherwise you have to write non-trivial cleanup code regardless of how you return errors. Try/catch (and especially finally) helps a lot because you get to group all your cleanup in one place. With error codes the code looks something like:

  a = acquire(A)
  if (!a) return

  b = acquire(B)
  if (!b) {
     release(a)
     return
  }

  c = acquire(C)
  if (!c) {
     release(a)
     release(b)
     return
  }

  ...
This is a maintenance nightmare. It's hard to see what the code is doing because the real logic is hidden between piles of error handling stuff. If you add a new resource acquisition in the middle you have to go over every statement that follows and modify error handlers. And don't you dare changing the order of statements, because that basically forces you to rewrite the whole function. Believe me, you don't want this in your code, exceptions are your friend :)

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

#107
post #102

Earlier quoted context omitted.

Inspired by Lisp's condition system I wrote a ruby library which comes pretty close to Lisp's error handling. It also implements "restarts" ... a little bit messy though since, as you said, low-level execption are used to get it working. In one point the condition system bootstraps itself which is quite interesting to think about. https://github.com/melkon/conditions An example ("parse_log_file" and "log_analyzer sho…

Have you considered using Ruby's throw/catch instead of exceptions? I did that for Atomy's condition system[1]. They worked great because you can just use the restart names for the throw/catch tags. [1]: https://github.com/vito/atomy/blob/master/kernel/condition.a...

I might have considered throw and catch as I wrote the library, but right now, I cannot think of any good reason why I haven't used it. Will check that again. Thanks for the suggestion.

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

#108
post #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 yo…

It was pointed out later in the thread that it should have been 'undefined' rather than 'null'.

I'm genuinely curious: how is returning undefined any different from returning null, in this case?

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

#109

Earlier quoted context omitted.

It was pointed out later in the thread that it should have been 'undefined' rather than 'null'.

I'm genuinely curious: how is returning undefined any different from returning null, in this case?

If you return null, there is no way to discern between invalid input data and 'null' as input.

If you return null for 'null' as input and undefined for invalid data, then you don't have to look at the input again to check whether you just failed to parse json or whether the input was just 'null'.

   if (HypotheticalJSON.parse(input) === null && input.trim() != 'null'){ alert('invalid input'); }
instead of just

   if (HypotheticalJSON.parse(input) === undefined){ alert('invalid input'); }
Though as I said in my comment, I do believe throwing an exception to be a valid action here - at least in any other environment than server-side JS where you have to be a bit careful.

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

#110

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?

It's not really an objection to terminology. "Fooglewoo" handlers would still exist outside the normal flow of control while handling things that many people would consider routine.

Burying that kind of every-day, expected-circumstance logic in a side channel is, at least in some developers opinions, detrimental to the readability and understandability of a program.

Post reply on HN