-
Notifications
You must be signed in to change notification settings - Fork 34
Programmable control flow primitives
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