Sometimes when I am programming, I find that some particular control structure would be very useful to me, but is not directly available in my programming language. I think my most common desire is something like a "split while" (I have no idea what to actually call this):
{
foo();
} split_while( condition ) {
bar();
}
The semantics of this code would be that foo()
is always run, and then the condition is checked. If true, then bar()
is run and we go back to the first block (thus running foo()
again, etc). Thanks to a comment by reddit user zxqdms, I have learned that Donald E. Knuth writes about this structure in his paper "Structured programming with go to
statements" (see page 279).
What alternative control structures do you think are a useful way of organizing computation?
My goal here is to give myself and others new ways of thinking about structuring code, in order to improve chunking and reasoning.
Note: I'm not asking about how to generalize all possible control structures, whether by using jne
, if
/goto
, Lisp macros, continuations, monads, combinators, quarks, or whatever else. I'm asking what specializations are useful in describing code.
Most languages have built-in functions to cover the common cases, but "fencepost" loops are always a chore: loops where you want to do something on each iteration and also do something else between iterations. For example, joining strings with a separator:
I know folds can cover this case, but sometimes you want something imperative. It would be cool if you could do:
D's scope guards are a useful control structure that isn't seen very often.
How about
for cycling through the available statements on each successive pass.
Edit: trivial examples
Edit 2: In the third example above the syntax is maybe a bit confusing as it looks like a function. In fact, only one statement is evaluated on each pass, not both. A better syntax might be something like
Or something to that effect. However I do like the idea that the result of which ever is called can be used if desired (as in the color examples).
Missing in every C-derived language.
Please consider before you vote or write a comment:
This is not redundant to
for (int i = 0; i <= UpperBound(); i++)
, it has different semantics:UpperBound()
is evaluated only onceThe case
UpperBound() == MAX_INT
does not produce an infinite loopWith (lisp-style) macros, tail-calls, and continuations all of this is quaint.
With macros, if the standard control flow constructs are not sufficient for a given application, the programmer can write their own (and so much more). It would only require a simple macro to implement the constructs you gave as an example.
With tail-calls, one can factor out complex control flow patters (such as implementing a state machine) into functions.
Continuations are a powerful control flow primitive (try/catch are a restricted version of them). Combined with tail-calls and macros, complex control flow patterns (backtracking, parsing, etc.) become straight-forward. In addition, they are useful in web programming as with them you can invert the inversion of control; you can have a function that asks the user for some input, do some processing, asks the user for more input, etc.
To paraphrase the Scheme standard, instead of piling more features onto your language, you should seek to remove the limitations that make the other features appear necessary.