
Exceptions for control flow considered perfectly acceptable - bensummers
http://www.drmaciver.com/2009/03/exceptions-for-control-flow-considered-perfectly-acceptable-thanks-very-much/
======
h2s

        > Argument by meaningless blither. What distinguishes
        > “exceptional conditions” from “control flow”? I have
        > reached the end of a million element list. This
        > happens one time in a million! That sounds pretty
        > exceptional to me!
    

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.

~~~
andyjpb
h2s: Can you explain to us what exactly _is_ the difference between the
implementation of flow control during exception throwing and all the other
kinds of flow control (including, but not limited to, stack popping).

~~~
astrobe_
IIRC no standard flow-control construct can do non-local returns (and that's
where the Evil lies).

~~~
andyjpb
How about call/cc and setjmp/longjmp ?

~~~
emn13
And those control flow methods are also widely considered to be tricky and
cause a maintenance burden.

~~~
shurcooL
Just making an observation here. The reason they are tricky and cause a
maintenance burden is because they create non-obvious dependencies. You'd have
to read a lot of seemingly unrelated code to spot them. Without the explicit
knowledge of these dependencies, your changes will have unexpected
consequences. (Hence, in a system that tracks all dependencies perfectly, this
might not be a problem. This is an experiment I'm trying to run right now.)

~~~
astrobe_
Exceptions have been called "glorified goto" for a reason. In fine, the OP
says that GOTOs are perfectly acceptable.

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

Keep doing your own thing.

~~~
andyjpb
I generally agree but I'd replace "unless they can show mathematical proof"
with "unless they can show a code profile".

Happy days!

~~~
moron4hire
I get your point, and that's pretty much what I meant. You need to have very
specific reasons. I would argue a code profile would only prove a specific
case, instead of a general case. But the point remains, "best practices"
aren't theorems. They are used by more programmers as CYA than as good
software development strategies.

------
reginaldo
_Writing exception safe code is hard

No it’s not. Be sure to clean up anything that could need cleaning up in a
finally block._

This is like saying... _be sure to never copy more bytes than the buffer
capacity_. Easier said than done.

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

Let me quote section 3.1:

 _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:_

    
    
      try {
      for (var idx = 0; idx < xs.length; idx++)
          xs[idx].update();
      } catch (e) {
          // ...
      }
    
    

_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 sufﬁcient since update may also have modiﬁed global variables and
other objects on the heap. Writing truly exceptionsafe code is difﬁcult and
error-prone._

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.

[1] <http://www.vpri.org/pdf/tr2011001_final_worlds.pdf>

~~~
btipling
How would you write this without exception handling, how would that make it
any easier? Perhaps do not put the entire loop in the try catch, but just the
single iteration.

~~~
reginaldo
Oh no. I'm not saying it would be easier without exceptions. I'm just saying
that the current status of our programming tools makes writing safe code very
hard, and exceptions are one more thing you have to think about. I use them a
lot...

The authors of the paper propose their "worlds" API as a way to make writing
safe code easier. They're still using exceptions, but they would require no
cleanup...

The code becomes:

    
    
      try {
          in thisWorld.sprout() {
              for (var idx = 0; idx < xs.length; idx++)
                xs[idx].update();
              
              thisWorld.commit();
          }
      } catch (e) {
          // no clean-up required!
      }
    

So it's commit for data structures for data structures. If an exception is
thrown and the commit line is not executed, no changes will be visible.

------
danielbarla
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
_currently_ for most mainstream languages (and yes, Python disagrees).

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.

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.

~~~
gleamer
The main problem with the idea of abusing exceptions as a control flow
structure is the fact that they were designed to subvert and obscure the flow
of control of any program that uses them. If people start to mindlessly pull
clever stunts such as relying on exceptions to implement their algorithms then
their code becomes unreadable, unmaintainable and unauditable. Not only their
code, but any code which happens to include it. Its only purpose is to create
an unmanageable pile of spaghetti code which is needlessly hard to trace. And
what good comes out of it?

~~~
danielbarla
Well, I tend to agree; but keeping an open mind, this might just be our
subjective rationalisation because we don't understand a newer / better
approach.

My point is just that even if the exception-raising approach was better, it'd
take a lot of time before it would become truly idiomatic and allow us to reap
its benefits, on a software engineering level. I know many would disagree with
me on this, however; I like to think I'm a realist.

------
AndrewDucker
I've used exceptions for flow control in validation before. Worked well.

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.

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.

(Obviously, this doesn't work if you want to return _all_ the things that are
wrong with the data.)

------
mtrimpe
I think it all depends on context. I use checked exceptions for handling edge
cases in Java, which turns something like this:

    
    
        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;
        }
    

into this:

    
    
        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);
        }
    

in which case I'm very much in favor of using exceptions as control flow
mechanisms.

Instead of just getting nulls to indicate failure I now even know exactly what
caused my error.

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.

~~~
arethuza
Interesting, I first looked at the second code segment and _really_ didn't
like it. However, I think thats just the whole Java checked exception thing
(which I think everyone now regards as a mistake) - if you removed the throws
and everything after it on that line it actually looks quite sensible and much
better than simply returning null to mean "it didn't work for some reason I'm
not going to tell you about".

~~~
mtrimpe
Exactly. It's essentially as close as you can (legibly) get to an Option/Maybe
monad in Java.

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

<http://jsperf.com/try-catch-error-perf/3>

~~~
sneak
Oh, wow. On an iPad mini, the exception code is over two orders of magnitude
slower in MobileSafari 6.

------
xenophonf
I'm reminded of Kent Pitman's essay "Condition Handling in the Lisp Language
Family" ([http://www.nhplace.com/kent/Papers/Condition-
Handling-2001.h...](http://www.nhplace.com/kent/Papers/Condition-
Handling-2001.html)):

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

------
baha_man
"Debuggers will break on exceptions... Decent debuggers allow you to specify
which exceptions you break on and which you don’t."

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.

I'm surprised this question and partial answer on Stack Overflow haven't got
more votes:

[http://stackoverflow.com/questions/5452480/how-to-save-
and-m...](http://stackoverflow.com/questions/5452480/how-to-save-and-manage-
debug-exceptions-preferences-in-vs2010)

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

<http://www.javaspecialists.eu/archive/Issue187.html> and
[http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html?pa...](http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html?page=2)
are two well written sources of many that Google turned up on the subject.

~~~
mcherm
I would encourage you to do that post. Because the two documents you linked to
are very unconvincing when placed beside David MacIver's essay.

The first link (<http://www.javaspecialists.eu/archive/Issue187.html>) says
the code was hard to understand, that this is the 'wrong' way to use
exceptions, that reusing a normal exception type instead of an exception
intended for control-flow might mask other exceptions, and that debuggers will
pause. These are MacIver's points #4, #2, #6, and #5 and he debunked each one.

The second link
([http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html?pa...](http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html?page=2))
says "This not only makes the code difficult to read, but also makes it
slower." That is MacIver's points #4 and #1 and he debunked them.

Do you feel that any of MacIver's points are incorrect? Do you know of any
arguments that he did not already address?

~~~
emn13
He didn't do any debunking. He merely asserted the opposite; and not very
convincingly.

He claims exceptions are fast enough. But though he proposes that exceptions
are generally usable, he only backs this up for java, and AFAIK the statement
is in general false. In other words, in most contexts, using exceptions for
control flow is expensive.

He claims that "decent debuggers" won't pause - but which decent debuggers is
he talking about? Because that's not at all the norm. Furthermore, as soon as
you attach a debugger, it's likely _all_ exceptions are much, much slower.
Having code that runs orders of magnitudes slower in debug mode is a problem
in and of itself because it means that some issues can't be properly debugged.
Furthermore, many debuggers are designed to work with convential code - in
other words, if they let you filter exceptions, it's not in a practical way
intended to be ideally usable as control flow.

He claims that it's not hard to understand, but provides no support. If you're
going to deviate from convention, you should have a reason; some argument.
Merely the fact that it _is_ conventional is a plus since that simplifies
communication and maintenance. And frankly, having read his article, I don't
see the advantage - he's doing it differently, but what's the point? What's he
winning?

He claims that the arguments against exceptions aren't well documented, but
that's simply because he's searching rather narrowly. All the way back to
dijkstra's article on goto such control flow existed, it just wasn't called
the same. And exceptions are essentially non-local goto's.

Finally, he's doing an end run around the type system. This is about as
problematic as a null reference; i.e. it's going to cause constant pain.
You've documented your program by type annotation which is good for humans,
good for API discoverability (autocomplete) and allows some static checking.
By doing this you're adding a hole that isn't properly annotated. In some
languages, e.g. java with checked exceptions, this is less of a problem (but
then it's also quite wordy). And again, it isn't true in general - maybe for
java.

In a purely functional language with checked exceptions, I can see his
argument holding water - Say, some Haskell variant. At that point, the
distinction between this approach and discriminated unions is very small -
indeed, if you use some nice monadic syntax sugar you could probably exchange
the one for the other.

But really, why not just use discriminated unions in the first place?

~~~
mcherm
> He claims exceptions are fast enough.

This is going to vary across languages. In cPython for instance (since I
happen to know it), exceptions are at least as fast as looping through an
iterator, since exiting from a loop is done via exceptions. He included a link
to an article showing that exceptions are quite fast on the JVM. I am sure
there are other languages where the implementation of exceptions is slow -- in
these languages this is a valid objection to using exceptions for flow
control. And I don't care how fast the code runs under a debugger. Perhaps you
do, but really, I don't; we must have very different use cases.

> He claims that it's not hard to understand, but provides no support. [...] I
> don't see the advantage - he's doing it differently, but what's the point?
> What's he winning?

It ISN'T hard to understand if used in a consistent way... I don't need any
further evidence of that than my own observations. But you are absolutely
correct that the argument needs evidence of exceptions being clearer. Perhaps
it would help to provide an example of a triple-nested loop with numerous
boolean condition variables contrasted with the same loop using exceptions for
exit. I don't think exceptions for flow control are more clear in all
circumstances, or even in most circumstances, but I believe that they are in
some circumstances, especially in cases where substantial work needs to be
done in order to determine whether one should proceed: doing the work twice is
inefficient, and splitting the function into part-A (everything before the
decision point) and part-B (everything after it) can be much less readable
than using an exception if part-A sets up variables and data structures used
in part-B.

> All the way back to dijkstra's article on goto such control flow existed, it
> just wasn't called the same. And exceptions are essentially non-local
> goto's.

No, I think they are fundamentally different. The problem with GOTO, and with
programming before structured programming was invented, was a problem with
arbitrary ENTRY points; arbitrary EXIT points do not cause this problem. My
more detailed thoughts on this can be found at
[http://mcherm.com/permalinks/1/in-defense-of-the-much-
malign...](http://mcherm.com/permalinks/1/in-defense-of-the-much-maligned-
goto)

> Finally, he's doing an end run around the type system.

This seems to be a completely new argument and one which wasn't addressed. I
am very interested, but somewhat confused. How does the use of exceptions
undermine the type system? Is it because the type of the function, instead of
being "Returns an Int" becomes "Returns an Int or raises an exception"? If
that happens for all functions, how is it confusing? Can you give me an
example of how things could go wrong?

> In a purely functional language with checked exceptions [...] if you use
> some nice monadic syntax sugar [...] the distinction between this approach
> and discriminated unions is very small. [...] why not just use discriminated
> unions in the first place?

I agree, as long as the language syntax supports doing it easily that is the
better approach.

------
TheMiller
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 _good_ idea.

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

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.

(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 _when_ one would want to use this mechanism:
[http://www.lispworks.com/documentation/HyperSpec/Body/s_thro...](http://www.lispworks.com/documentation/HyperSpec/Body/s_throw.htm))

~~~
DRMacIver
Given that the article was a response to criticism of a previous proposal of
mine on grounds that it used exceptions for control flow, and given that I
linked to that discussion (on the page for the proposal in question) in the
opening paragraphs of this one I probably felt that the reasons for using
exceptions for control had been adequately covered at that point.

But I was probably not trying to suggest you should regularly do this
(certainly I wouldn't suggest that now), only that if you find you have a good
reason to do it you shouldn't be afraid of it.

~~~
TheMiller
Sorry I didn't follow the link. Given the link's text, "I have been invited",
I didn't expect it to lead to background information, but rather just to,
well, an invitation. My bad.

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

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

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.

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.

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

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.

'/s/Exceptions/GOTO/g' and you have essentially the same argument

~~~
mcherm
> '/s/Exceptions/GOTO/g' and you have essentially the same argument

Absolutely untrue. Eliminating GOTO was a major step forward in programming
language design, one better known as "Structured Programming". The advantage
was that it eliminated random entry points so that bits of code
("subroutines", "methods", or "functions") could be reasoned about independent
of the entire program by starting from the "top" and working forward.
Arbitrary exit points (like exceptions, break, and return) still permit this
reasoning; allowing GOTO to target arbitrary statements makes it impossible to
reason this way.

For a better explanation, see this essay I wrote on the subject:
[http://mcherm.com/permalinks/1/in-defense-of-the-much-
malign...](http://mcherm.com/permalinks/1/in-defense-of-the-much-maligned-
goto)

~~~
dkhenry
So exceptions do add structure as to where you can go _to_ but they serve the
same purpose in where you can come _from_ Its a little easier to trace since
you are scope bound, but its still harder then being able to trust the control
flow of your code. Additionally because you can't trust control flow of your
code ( since any time the sub routine can essentially longjump to some place
higher in your stack) you are now required to context wrap all your code in
try blocks essentially implementing bookkeeping that the compiler will do for
free if you just design your code in a sane manner.

This is why java implemented typed exception throwing because it the only way
to have some semblance of safety when programming with exceptions. I am even
more disheartened to see that the author uses my beloved scala and in still
trying to do this kind of nonsense, when we have plenty of good tools at our
disposal to negate the use of exceptions for control flow.

~~~
mcherm
I'm not completely sure I am understanding you.

I think that RAISING exceptions is just a non-local exit point, like a break
or return which does not make it difficult to reason about one piece of code
in isolation from others.

I think that CATCHING exceptions is a clearly marked 'entry' point: one can
only arrive in an exception handler from an exception raised within the
corresponding try statement, and the place that you arrive is clearly marked.

The one bit that is more confusing is throwing right through without an
exception handler: in other words, code you call might raise an exception
which your code does NOT catch, and thus exit your function prematurely: you
might thus allocate some resources and fail to deallocate them safely.

Are we saying the same thing here?

~~~
dkhenry
Somewhat. You are correct to say were know that the exception was raised in
the try block so we have an idea about where it came from, but unless each try
block is one statement long you don't know where the exception came from .
That's the disconnect. When in a try/catch block you know where your going (
the catch ), but you don't know where you came from. That is almost as
problematic as GOTOs in that planning for all program states is once again a
headache ( did I open that socket , is that memory free'd ,... )

~~~
mcherm
I see what you are saying. I think I avoid this problem by having a policy of
not modifying fields arbitrarily within a try statement.

Let me try to give some examples. I write things like this:

    
    
      Person p = getThePerson(id);
      try {
          storePersonToDatabase(p);
      } catch(DatabaseException err) {
          generateAlert('Could not save person');
      }
      doMoreProcessing(p);
    

In this case I know that p was initialized because it happened outside of the
try statement. But I try never to do things like this:

    
    
      Person p = getPrimaryAccountHolder();
      try {
          storePersonToDatabase(p);
          p = getSecondaryAccountHolder();
          storePersonToDatabase(p);
      } catch(DatabaseException err) {
          generateAlert('Could not save person');
      }
      doMoreProcessing(p);
    

If I did that, then there would be no way to know whether p was the primary
account holder or the secondary after the try statement when I call
doMoreProcessing(). On the other hand, it's perfectly OK for me to do this:

    
    
      Person p = getPrimaryAccountHolder();
      try {
          storePersonToDatabase(p);
          Person p2 = getSecondaryAccountHolder();
          storePersonToDatabase(p2);
      } catch(DatabaseException err) {
          generateAlert('Could not save person');
      }
      doMoreProcessing(p);
    

...because with this pattern I don't know, after the try-catch, whether the
variable p2 has been initialized or not, but I also don't care because it is
out of scope and can't be used.

If I didn't follow this practice, then I think the problem you describe would
be an issue for me: not knowing which of several possible locations was the
source of the exception would mean I didn't know how the variables had been
set. Interesting... I learned something today.

~~~
dkhenry
I think we are on the same page now. What your describing works well If you do
it _everywhere_ and also _require_ exceptions to be handled, much like Java
does (mostly) in c++ its a total crap shoot since destructors don't run if you
pop their stack.

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

However they are only few good reasons to use goto, and exceptions for control
flow should be treated the same.

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.

Nobody likes goto (and my bad english)

bye

------
gte910h
It entirely depends on the language as to the level of acceptability of using
exceptions for control flow. In Java, it's _moderately_ 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.

In Objective C, exceptions are "he's dead Jim" territory.

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.

~~~
BruceM
Many years ago, there was a language called TOM. TOM was a descendant of
Objective C, but with garbage collection, blocks, some other stuff ... and a
Common Lisp style condition system (before Objective C had exceptions or
blocks or GC or ...).

<http://gerbil.org/tom/>

Sadly dead once the author got his PhD though.

~~~
gte910h
> garbage collection, blocks

Blocks exist in Objective C. GC did, but was replaced for Automatic Reference
Counting (ARC).

ARC is good enough in mobile and probably better for Desktop.

~~~
BruceM
Let me quote a couple of relevant parts of my comment:

> Many years ago

> (before Objective C had exceptions or blocks or GC or ...)

TOM had the things that I mentioned back in 1998, 1999, maybe earlier.

Objective C has come a long way since then.

------
guilloche
Yeah, sometimes, using exception as control flow is the only simple and clear
way. I do use it occasionally.

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.

So the function can be implemented as:

void A()

{

    
    
      try {
        A1();
      }
      catch (e) {
        A2();
      }
    

}

void A1()

{

    
    
      .....
      if(corner case) raise();
      .....
    

}

Is there a simple way to avoid using eceptions here?

~~~
MereInterest
Yup. Have some sort of error code that is passed back by A1() or A2().

    
    
      bool A1();
      bool A2();
    
      void A(){
          bool result = A1();
          if (!result){
              A2();
          }
      }
    

Instead of your "if(corner case) raise();", you would then have a "if(corner
case) return false;".

However, it becomes more difficult if you want a return value. Suppose that
your A() function was as follows.

    
    
      double A(){
          double result;
          try{
              result = A1();
          catch (e) {
              result = A2();
          }
          return result;
      }
    

Then, you are already using the return value to indicate something other than
success or failure of the operation. You could have A1 and A2 return some
special value that wouldn't return normally. For example, if it is some
distance, negative values could represent invalid responses.

    
    
      double dist(){
          double output = dist1();
          if (output==-1)
              output = dist2();
          return output;
      }
    

However, sometimes any value could be a valid value. Then you need to pass
things by pointer or reference in order to have two outputs, one for the value
and one for the success/failure.

    
    
      bool A1(double* output);
      bool A2(double* output);
    
      double A(){
          double output;
          bool success = A1(&output);
          if (!success)
              A2(&output);
          return output;
      }
    

It is in this last case when exceptions start being much cleaner, since they
provide a clean way to indicate that the operation has failed.

------
bjourne
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?

Because programming is just as much about _communicating intent_ 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.

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

Following the Samurai Principle (<http://c2.com/cgi/wiki?SamuraiPrinciple>)
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.

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.

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

    
    
        try: return int(somestr) 
        except ValueError: return None 
        

Often the string you're passing to int() is user input so you _expect_ it to
often be non-numeric.

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

