Skip to content

Programmable control flow primitives

jckarter edited this page Apr 16, 2011 · 3 revisions

When you have lambdas and exceptions in the core language, much of what we think of as core language apparatus is just as well programmed in the standard library, given good enough syntactic support.

In particular, loop "break" and "continue" statements are not really any different (using C++ notation) from "throw Break()" or "throw Continue()" to well placed catch blocks. Then, a statement like "while" takes a pair of lambda arguments and wraps calls to the second in such a try/catch block.

Similarly, a "return x" statement is no different from "throw Return(x)", presuming that the regular function wrapper catches Return& and yields up x as the function result.

Switch statements are much improved by defaulting to break at the end of each case, but allowing you to "throw Continue_at_case(Y)". Conceptually this could be thought of as caught by an implicit loop around the switch statement, but of course an optimizer could bypass that and branch or fall through directly to the selected case when Y is known at compile time.

Do we need more than one built-in control construct? A looping switch can do everything (e.g. for if, "switch (predicate) case true: { ... } default: { ... }") and then be dressed up (i.e., limited) with adapters in the library.


For a first-pass implementation of programmable control flow primitives, I'm thinking of just having lambdas be forced-inline and making return/continue/break transparent to lambdas, similar to how blocks work in Smalltalk. A more general "static exception" sort of feature might be a natural outgrowth of that. Break/continue/return are different from exceptions in that you really want them to be statically resolved; you don't want to suffer runtime termination because your "break" statement has no matching "catch (Break)" block. -Joe