Is there really no way to decouple non-local control-flow constructs (which seem useful in general!) from exceptions? (JVM byte-code has labeled jumps for a reason I guess).
In my mind using exceptions for control-flow looks just completely wrong. (And I think this is also what gets taught mostly[1]).
Exceptions are exceptional: They are there to recover on a higher level form really bad error situations. Most of the time you should not even try to catch them in your code, because recovery form a really bad error is very often impossible to correctly achieve locally anyway. (Only your supervisor may know what to do when you’re seriously ill, or die). Please see also the linked SO answers for that line of reasoning.
Languages like Java or Python are a terrible example OTOH, as they routinely (mis)use exceptions for control flow. I think we should not imitate that.
I like the idea of boundary / break
that @odersky proposed on GitHub because it’s not an unbounded goto
(like exceptions!) but still structured programming; but I think it should not be leaky.
I think, if I would dig into how it works I would be annoyed if I would find (slow and heavyweight) exceptions—as this mostly kills the purpose as a fast “ejector seat” form some long running task. And I would be even more annoyed if those exceptions would interoperate in any way with regular, user-level, exceptions.
This whole discussion here wouldn’t be needed if control-flow would be cleanly separated form exception handling. This are imho two different topics and therefore should be handled completely separately. Mixing unrelated things always creates much to many gotchas that will bite people in unexpected and very annoying ways (as we actually just see here with the interaction of those control “exceptions” with everything around). @odersky is right that this is terrible. But making the already bad and leaky abstraction fully transparent as a consequence is even worse!
And while I'm here, maybe I should mention something that I don't understood in this context: Why the hell does Scala still include `return` (in the Java sense)? This should not exist at all as it's just two different ways to do the same thing. There is absolutely no advantage to have a `return` keyword in the language for *normal* function return. That's just one more thing to explain to new people: "Sure, you could write 'return' here at the end as in Java, but we actually never do that." Usual newbie reaction: "WTF?!".
If there would be no “regular” return
in the language, there would be also no problem to use that keyword for non-local returns… And we could bikeshed whether break
or return
would match up better with boundary
.
I’ve just remembered one likes to have “multiple returns” in some cases, and than you would need such keyword (even multiple returns are considered a code smell in some circles; but I would not sign this claim, I guess).
But how about streamlining this idea: Multiple returns get used for the same purpose as no-local returns in deeply nested scopes: To abort
tasks early!
So I think I would rename return
to abort
(even in the case of non-local control flow), and make it at the same time an error to use abort
as last statement. That way abort
would be reserved to actually always abort something. (And it should be still not implemented as exceptions even in the case of no-local abort! As aborting something is not something exceptional, and not error handling, but part of the happy path of execution, imho). bounded
/ abort
sounds also fine to me. I guess abort
would even make sens intuitively in the context of Futures. This spontaneous idea looks like a win.
[1] anti patterns - Are exceptions as control flow considered a serious antipattern? If so, Why? - Software Engineering Stack Exchange