TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Exceptions for control flow considered perfectly acceptable

51 pointsby bensummersabout 12 years ago

18 comments

h2sabout 12 years ago
<p><pre><code> &#62; Argument by meaningless blither. What distinguishes &#62; “exceptional conditions” from “control flow”? I have &#62; reached the end of a million element list. This &#62; happens one time in a million! That sounds pretty &#62; exceptional to me! </code></pre> Unless you were expecting the list to have infinite length, then this would be a misuse of exceptions. The true logical fallacy here is the author of this post's argument from personal incredulity. The fact that he hasn't yet learned how to distinguish between exceptional conditions and control flow doesn't mean that it's an impossible or meaningless distinction.
评论 #5324107 未加载
评论 #5324130 未加载
评论 #5324054 未加载
评论 #5324048 未加载
moron4hireabout 12 years ago
I agree with you. There are way too many cases of people making generalized arguments "you shouldn't do XYZ in programming because it's slow/confusing/etc" that really just have no place being uttered unless they can show mathematical proof it is too much to bother with in <i>every</i> situation. Back in the 80s and early 90s it was "no compiled language should ever be used for critical software", and then in the late 90s and early aughts it was "no VM'd language". Now what? It's all there is! You'd be nuts to NOT use a VM'd language. And the only reason we know any better is because people ignored the received wisdom and just did their own thing.<p>Keep doing your own thing.
评论 #5324157 未加载
评论 #5324075 未加载
reginaldoabout 12 years ago
<i>Writing exception safe code is hard<p>No it’s not. Be sure to clean up anything that could need cleaning up in a finally block.</i><p>This is like saying... <i>be sure to never copy more bytes than the buffer capacity</i>. Easier said than done.<p>Writing exception safe code is very hard. Do not take my world for it. Read Alessandro Warth's paper (with Alan Kay as a co-author) [1]. Do not skip section 3...<p>Let me quote section 3.1:<p><i>In languages that support exception-handling mechanisms (e.g., the try/catch statement), a piece of code is said to be exception-safe if it guarantees not to leave the program in an inconsistent state when an exception is thrown. Writing exception-safe code is a tall order, as we illustrate with the following example:</i><p><pre><code> try { for (var idx = 0; idx &#60; xs.length; idx++) xs[idx].update(); } catch (e) { // ... } </code></pre> <i>Our intent is to update every element of xs, an array. The problem is that if one of the calls to update throws an exception, some (but not all) of xs’ elements will have been updated. So in the catch block, the program should restore xs to its previous consistent state, in which none of its elements was updated. One way to do this might be to make a copy of every element of the array before entering the loop, and in the catch block, restore the successfully-updated elements to their previous state. In general, however, this is not sufficient since update may also have modified global variables and other objects on the heap. Writing truly exceptionsafe code is difficult and error-prone.</i><p>Now, I have seen a lot of code, and very very very few times I've seen someone restoring the state of a collection after an exception blows.<p>[1] <a href="http://www.vpri.org/pdf/tr2011001_final_worlds.pdf" rel="nofollow">http://www.vpri.org/pdf/tr2011001_final_worlds.pdf</a>
评论 #5324212 未加载
评论 #5324261 未加载
评论 #5324164 未加载
评论 #5325130 未加载
评论 #5324205 未加载
danielbarlaabout 12 years ago
I think this argument is generally taken out of context; my biggest concern would indeed be that using exceptions for control flow is non-idiomatic <i>currently</i> for most mainstream languages (and yes, Python disagrees).<p>This means that going against the grain will cost you time (and not you necessarily, but your company / colleagues, etc), and that time better come with some great benefits for it to be worthwhile.<p>So really, the argument can be looked at from many angles, depending on what value system you are using / what you would like to optimise for. I like to optimise for least surprises / development time.
评论 #5324155 未加载
AndrewDuckerabout 12 years ago
I've used exceptions for flow control in validation before. Worked well.<p>Basically, you have nested validation code, and the second you hit something which invalidates your data you throw an InvalidDataException(X), catch it at the top of the validation, and then report back to the user that their input is broken because of X.<p>The alternative was that every method would need to pass back whether it had found a validation error, and every place that called one would need to check that returned value. Huge numbers of lines of code, for no real gain.<p>(Obviously, this doesn't work if you want to return _all_ the things that are wrong with the data.)
评论 #5324310 未加载
mtrimpeabout 12 years ago
I think it all depends on context. I use checked exceptions for handling edge cases in Java, which turns something like this:<p><pre><code> public Session startByInterviewId(Long interviewId, String email, String name) { Session session; Interview interview = interviewService.getPublicById(interviewId); if (interview != null) { Account user = userService.createUser(name, email, interview.getLocale()); if (user != null) { session = startByInterview(interview, user); } } return session; } </code></pre> into this:<p><pre><code> public Session startByInterviewId(Long interviewId, String email, String name) throws Interview.NotActive, Interview.NotPublic, Interview.DoesNotExist, Account.EmailExists { Interview interview = interviewService.getPublicById(interviewId); Account user = userService.createUser(name, email, interview.getLocale()); return startByInterview(interview, user); } </code></pre> in which case I'm very much in favor of using exceptions as control flow mechanisms.<p>Instead of just getting nulls to indicate failure I now even know exactly what caused my error.<p>I would never even think of writing code like this in JavaScript or Clojure though and I'd guess is that in Scala/Haskell a custom Option would be much better.
评论 #5324213 未加载
评论 #5324227 未加载
评论 #5324379 未加载
评论 #5324247 未加载
btiplingabout 12 years ago
Discussions about performance are statements of fact and can be measured. A jsperf shows that code executing in a try catch for chrome on a mac can be up to 3% slower for me[1]. Let's just get the numbers and show them and if they're valid they're valid, if not let's just dispel the rumors. Arguments about code architecture or best practices for intangible reasons are bikesheds. Just do what you like and be consistent and that's good enough. So if you can't demonstrate slowness, can't demonstrate a real problem as in the code wont work, then there is no real argument. In JavaScript avoid exceptions as control flow though, because they really are slower.<p><a href="http://jsperf.com/try-catch-error-perf/3" rel="nofollow">http://jsperf.com/try-catch-error-perf/3</a>
评论 #5324263 未加载
xenophonfabout 12 years ago
I'm reminded of Kent Pitman's essay "Condition Handling in the Lisp Language Family" (<a href="http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html" rel="nofollow">http://www.nhplace.com/kent/Papers/Condition-Handling-2001.h...</a>):<p><i>To properly understand condition handling, it is critical to understand that it is primarily about protocol, rather than mere computational ability. The establishment of protocols is a sort of before-the-fact hedge against the "prisoner's dilemma"; that is, it creates an obvious way for two people who are not directly communicating to structure independently developed code so that it works in a manner that remains coherent when such code is later combined.</i>
baha_manabout 12 years ago
"Debuggers will break on exceptions... Decent debuggers allow you to specify which exceptions you break on and which you don’t."<p>This drives me mad in Visual Studio, if you specify a set of exceptions to break on, then later decide you need to catch all exceptions, there's no easy way to go back to the first set.<p>I'm surprised this question and partial answer on Stack Overflow haven't got more votes:<p><a href="http://stackoverflow.com/questions/5452480/how-to-save-and-manage-debug-exceptions-preferences-in-vs2010" rel="nofollow">http://stackoverflow.com/questions/5452480/how-to-save-and-m...</a>
pauldbourkeabout 12 years ago
I was going to do a post rebuking the points made, but rather unsurprisingly it seems plenty of others already have done so, in a manner much less arrogant than OP's.<p><a href="http://www.javaspecialists.eu/archive/Issue187.html" rel="nofollow">http://www.javaspecialists.eu/archive/Issue187.html</a> and <a href="http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html?page=2" rel="nofollow">http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html?pa...</a> are two well written sources of many that Google turned up on the subject.
评论 #5324216 未加载
评论 #5324204 未加载
评论 #5324201 未加载
TheMillerabout 12 years ago
The author notably tries to refute arguments against the use of exceptions for control flow, but doesn't present any reasons (at least not in this article) as to why this usage might be a <i>good</i> idea.<p>There's no compelling reason to introduce odd, non-idiomatic code patterns when they don't confer a significant benefit. Some people here argue that the "intent" of exceptions in a language design is not relevant compared to what <i>can</i> be done with them. In general, I disagree with this. Language designers' intent informs the expectations of readers of code, and your readers' expectations are important. Code is a form of writing for communications, both with the computer and with maintainers; it's not artistic writing, where you might deliberately violate expectations or norms in order to delight or surprise your audience.<p>That said, using exceptions as a method of transferring control to a non-local, dynamically-bound location is a powerful technique for which few languages offer an explicit alternative. It's also difficult for readers to analyze, so it should be used sparingly. For instance, I can think of reasons that one might use this technique within a container or algorithm library, but I can't think of a good reason for a container library to force this control flow idiom on callers by throwing exceptions to signal common situations.<p>(As usual, Common Lisp is unusual here. It has a throw/catch feature which is explicitly a flow control mechanism, and not just an error-handling mechanism. The standard documentation is interesting in that the Notes section suggests exactly <i>when</i> one would want to use this mechanism: <a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_throw.htm" rel="nofollow">http://www.lispworks.com/documentation/HyperSpec/Body/s_thro...</a>)
评论 #5325241 未加载
评论 #5325244 未加载
评论 #5325242 未加载
Chris_Newtonabout 12 years ago
I couldn’t agree more and have long been arguing that we should use exceptions when they are a useful tool for the job because their semantics do what we need at the time. Sometimes that means exiting early because you can’t do what you’ve been asked to for some reason. Other times it means exiting early because you’ve already done everything you were asked to and there is no point in continuing further.<p>The main thing I would add to the original article is that the author is being a little kind to the critics on some of those points. For example, not only do exceptions not inherently need to be slow, they can actually be <i>faster</i> than the “classical” equivalent via return codes and the like. This is essentially because any jump-table-based exception mechanism means the non-exceptional control path can omit all the test logic that would serve only to exit the current block early. That could both reduce the size of the non-exceptional code and reduce the number of potential branches, each of which can be helpful for optimization. Although it’s rather less significant in performance terms because it only tends to happen once, when an exception does occur you also don’t have to run through all the individual levels of unwinding the stack with a jump table approach, as you can jump straight to levels that actually need to do something on their way to handling the exception and skip over anything that was just going to return immediately anyway.<p>As another minor data point, I haven’t found exceptions in C++ to be slow. Most/all of the major compilers seemed to have moved to a table-driven approach last time I used a broad set of them. The nasty overhead in C++ is more likely to be in the size of the generated executables; I’ve seen a compilation with exceptions disabled shave nearly 1/3 off the executable size.<p>Of course exceptions have somewhat different meanings and can have very different implementation overheads in different languages, so I’m not arguing that all advice to use them sparingly is bad. As always, it’s important to separate the dogma from the rational arguments.
dkhenryabout 12 years ago
Back in my early years as a software developer I once though that I could make some really eligent code by using exceptions for control flow. I used it to do a form of what I now know is pattern matching. It really cleaned up the code and made it super easy to extend and read, but it was a _terriable_ idea. It was slow and since nothing was checked by the compiler I found myself often at my root catch block trying to figure out how my nested catches didn't work.<p>Exceptions are not suitable for control flow. Yes they work and can sometimes give nice features, but typically they are just showing that you have poorly designed code and should be doing something differently.<p>'/s/Exceptions/GOTO/g' and you have essentially the same argument
评论 #5324226 未加载
carlosanteloabout 12 years ago
Exceptions break normal encapsulation mechanisms but as long as you code is exception safe, nobody cares, it's just that exceptions are the new goto, and nobody likes goto.<p>However they are only few good reasons to use goto, and exceptions for control flow should be treated the same.<p>Therefore the point we should make against exceptions for control flow is not exceptions are for exceptional circunstances but; as a rule of thumb exceptions are for errors. And indeed they help a lot in not obscuring normal program logic, we allready have other tools for control flow.<p>Nobody likes goto (and my bad english)<p>bye
gte910habout 12 years ago
It entirely depends on the language as to the level of acceptability of using exceptions for control flow. In Java, it's <i>moderately</i> routine to get a random exception or two that you recover from and go along your way merrily. Python similarly is A-OK much of the time.<p>In Objective C, exceptions are "he's dead Jim" territory.<p>Some of the differences of use are caused by the implementation of exceptions in those environments and the expectations programmers of libraries in those environments to what happens when exceptions occur.
评论 #5325188 未加载
guillocheabout 12 years ago
Yeah, sometimes, using exception as control flow is the only simple and clear way. I do use it occasionally.<p>ex. Lets assume that a problem can be attacked as algorithm1 (A1), and algorithm2 (A2). A1 is fast but cannot handle some corner cases while A2 is slow and can handle all cases. we also assume that there is no easy way to tell whether A1 is good or not without invoking A1.<p>So the function can be implemented as:<p>void A()<p>{<p><pre><code> try { A1(); } catch (e) { A2(); } </code></pre> }<p>void A1()<p>{<p><pre><code> ..... if(corner case) raise(); ..... </code></pre> }<p>Is there a simple way to avoid using eceptions here?
评论 #5324670 未加载
bjourneabout 12 years ago
The reason why using exceptions for control flow is bad is because it violates the Samurai Principle. Now why do I refer to a cheesy made up principle instead of explaining what I mean? Why do people use "exceptions are for exceptional situations" and similar empty expressions?<p>Because programming is just as much about <i>communicating intent</i> as it is about writing efficient code! Following guidelines and maxims is extremely useful because if both the writer and the reader understands the protocl, then communication is smoother.<p>The "Exceptions are for exceptional circumstances" protocol means that the reader of the code doesn't have to wonder "Is this a control flow situation? Is this exception supposed to be handled? Where does the code resume?"<p>Following the Samurai Principle (<a href="http://c2.com/cgi/wiki?SamuraiPrinciple" rel="nofollow">http://c2.com/cgi/wiki?SamuraiPrinciple</a>) similarily eases the cognitive load of the person reading the code. It allows you to treat each callable piece of code as an isolated unit whose value is equal to what it returns. For non-critical code, you can completely forget about exception handling because you dont need to bother. However, if an exception is thrown you can be equally assured that something unexpected happened. It was to hard for the "samurai function" to handle. Simple and extremely convenient.<p>One example of not following the Samurai Principle or "exceptions for exceptional situations" happened at my last job. We were an mobile payment processor and trying to issue a charge to a customer when their balance was to low would result in a BalanceToLowException. Except that wasn't anything out of the ordinary, customers would often not have enough funds! The situation would be handled by retrying the transaction some other day. The API for charging customers would better have been designed returning a two tuple (chargeStatus,errorMsg) so that the following code could continue in the same location whether the charge succeeded or not. Throwing exceptions for ordinary events lead to spaghetti code.<p>You can see similar misdesigns in some database ORM:s in which some queries throw silly NoRecordsFoundException which user code is forced to handle. Or Python's classic<p><pre><code> try: return int(somestr) except ValueError: return None </code></pre> Often the string you're passing to int() is user input so you <i>expect</i> it to often be non-numeric.
kenkoabout 12 years ago
Oleg Kiselyov uses exceptions for control flow in his Delimcc library for Ocaml, and if that doesn't establish that doing so is perfectly acceptable, I don't know what could.