Useful alternative control structures?
Asked Answered
M

28

42

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.

Misconstrue answered 27/11, 2010 at 20:27 Comment(9)
Re: your example. If the undo parts are just intended as examples, then what you have there is not a very "alternative" control structure. It's called exception handling and has existed (although not necessarily under that name) for almost as long as programming itself. If you do intend the undo s to be part of the semantics, then it's a transaction and isn't very alternative, either.Transudation
Note to confused readers: I have edited my question to emphasize my question and de-emphasize particular examples. In particular, I removed one example which the preceding comment references.Misconstrue
Needs to be community wiki to avoid closing for subjectivity (no real answer).Claro
Big list, "I find that ...", generally speculative 'cause the question is about control structures not implemented (or not widely known). This question doesn't really fall crashing to the ground anywhere in particular, but it is suspicious lots of different ways. And 5 hours in the answers are about ways to avoid needing new control structures or ways to build the example from existing ones...I'm going to go with NaRQ.Crag
For the "split_while", in Sather you can do loop statement1; while!(condition); statement2; end;Dumbarton
FWIW such a control structure (splitWhile) can be implemented pretty easily in Scala: paste.pocoo.org/show/297023 :-)Were
Even easier in Clojure: gist.github.com/718750 :DRenteria
I posted a similar question on Programmers.Se: programmers.stackexchange.com/q/22070/389Cobalt
@bigown: Thanks. Hopefully that will generate some new answers, if the question is not reopened here.Misconstrue
M
20

One that's fairly common is the infinite loop. I'd like to write it like this:

forever {
  // ...
}
Morphia answered 28/11, 2010 at 2:12 Comment(15)
#define ever (;;) for ever {}Montfort
@Jookia: #define forever for(;;)Dumbarton
I'd prefer repeat over forever, but maybe they're separate concepts.Nummulite
@Peter Gibson: normally you repeat something until some condition, like in Pascal.Dumbarton
@Jordão: forever is a long time - repeat implies that you might break out at some point. It would be like repeat... until(false) - where you leave the until(false) bit out because it is ugly :)Nummulite
Forever is the intent, but I agree; repeat, or even loop, would also work out.Dumbarton
Scala: def forever(f: => Unit) { while(true) f }.Were
@missingfaktor: I still want to be able to use break and continue. For your code, break turns to return; but continue is not addressed.Dumbarton
@Jordão: Scala doesn't have either of these control constructs - break, and continue. It's a primarily a functional language, and imperative features though available are generally discouraged. Due to popular demand, they recently provided break(though in the form of a library method). We still don't have continue (and I don't think we'll ever have, as you hardly need to write your hand-rolled loops in a functional language.)Were
@Jordão: and oh yes, you can use this library break in the forever control construct I defined in my second last comment above.Were
forever is certainly a lot prettier than while(true)!Are
Microsoft's QBASIC had "Do...Loop", without conditions, which would run until an "Exit Do" was executed. VB.Net provides the same statement. Ironically, what I find myself wanting in VB is a control statement to express the intent "just do the following once" (sometimes to allow a break-out; more often to define a variable's scope).Blubbery
@supercat: I've often used nested scopes in C# for that (but there's no break-out); but this is a general indication that you need to refactor some code to a new method. To do it once, you can use a do { ... } while(false) construct, but semantically, a once { ... } would be better. Maybe you can add this one to this question. I've also thought about the never { ... } (or dont { ... }) construct, as just a compiler backed way to comment-out some code. But I didn't think of many advantages to add it to this question. What do you think?Dumbarton
@Jordão: I don't especially like "once" as a word, but I'm not sure what would be better. Maybe just "Block" for a word-paired language like VB, so it could be paired with "End Block". For C derivatives, one could use braces without any keyword if one doesn't need the jump-to-end semantics, though it may be nice to have some marker that the brace-pair exists for scoping (rather than to delimit an "if" that accidentally got deleted).Blubbery
@supercat: makes sense, add it to this question then.Dumbarton
M
20

Sometimes, I need to have a foreach loop with an index. It could be written like this:

foreach (index i) (var item in list) {
  // ...
}

(I'm not particularly fond of this syntax, but you get the idea)

Morphia answered 28/11, 2010 at 3:14 Comment(4)
In python this is handled using the built in enumerate function which takes a list and returns a list of (index, item) pairs. "for i,item in enumerate(list)".Nummulite
Definitely! I've often written a foreach loop, but then realized I need an index later.Misconstrue
In Ruby we use Array#each_with_indexGrivation
In Harbour you have item:__enumIndex to retrieve it. Also, you can use item:__enumIsFirst and item:__enumIsLast that return bool. Worth notice that Harbour also permits descending foreach, and foreach with multiple arrays at same time. Descending is very useful to delete items during the loop without sync issues.Horehound
W
19

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:

string result = "";
for (int i = 0; i < items.Count; i++) {
    result += items[i];
    if (i < items.Count - 1) result += ", "; // This is gross.
    // What if I can't access items by index?
    // I have off-by-one errors *every* time I do this.
}

I know folds can cover this case, but sometimes you want something imperative. It would be cool if you could do:

string result = "";
foreach (var item in items) {
    result += item;
} between {
    result += ", ";
}
Woven answered 28/11, 2010 at 8:59 Comment(9)
I like it but would 'item' be in scope during the 'between' block, and if so, is it the previous or next item? If I wanted to turn something like ["a", "1", "b", "2"] into "a=1,b=2" then I need to alternate between "=" and ",". How would I get a loop index in the between block? Or do I need a non-local variable?Corrody
That'd be nice. The split_while addresses this concern, though only for while and not the other common loops.Misconstrue
@Andrew, you could always provide both the previous and next items in the loop: between(prev, next) {.Woven
In Haskell using "intersperse" that would not be a chore, imho.Unconsidered
@Andrew, that's the whole point of this. The between block would only be executed between two items, so not after the last.Woven
@minificent: bah, that's what happens when I come back to an SO thread after months away.Corrody
you should not be looping for this, but join(array, ',')Kaolin
@Chii, What does join do in that example?Revalue
@Shurane: join in this example is meant to be the function which takes an array, and concatenates each element, separated by the 2nd argument (the , in this case). most languages have this built in, such as the javascript Array.join.Kaolin
M
18

Loop with else:

while (condition) {
  // ...
}
else {
  // the else runs if the loop didn't run
}
Morphia answered 28/11, 2010 at 3:57 Comment(5)
If the loop does run, foo wont be ran the first time it runs, only at the end. It's the opposite of what he described.Renteria
Python has exactly this construction. Also, it allows to add 'else:' to 'for:' and 'try:'.Aceydeucy
In Python the else runs if the loop terminated "normally", either it executes without a break or never ran.Crescin
+1, but for me it's mostly the wish for a for(){...} else {...}Cistercian
@tstenner: I include that in my question when I say "Loop" with else. It's just that I've provided a while loop example. But yes, the idea is to have any loop type with an else.Dumbarton
W
13
{
    foo();
} split_while( condition ) {
    bar();
}

You can accomplish that pretty easily using a regular while:

while (true) {
    foo();
    if (!condition) break;
    bar();
}

I do that pretty frequently now that I got over my irrational distaste for break.

Woven answered 27/11, 2010 at 21:12 Comment(4)
That's true, but I feel this doesn't address the question. I don't particularly care about how you choose to implement these alternative control structures, whether with while and break or (gasp!) even goto. I want ways of thinking about code. I have found that split_while lets me think about the structure in a new way, analogous to how while is a structural improvement over a conditional jump.Misconstrue
This doesn't answer the OP question.Cobalt
Ppl isn't reading the question. It's strange to see this "answer" top voted.Cobalt
Maybe the implicit point of this answer is that there is already enough control structures - why add more language support for them when you already have a good enough abstraction?Haploid
C
13

If you look at Haskell, although there is special syntax for various control structures, control flow is often captured by types. The most common kind of such control types are Monads, Arrows and applicative functors. So if you want a special type of control flow, it's usually some kind of higher-order function and either you can write it yourself or find one in Haskells package database (Hackage) wich is quite big.

Such functions are usually in the Control namespace where you can find modules for parallel execution to errorhandling. Many of the control structures usually found in procedural languages have a function counterpart in Control.Monad, among these are loops and if statements. If-else is a keyworded expression in haskell, if without an else doesn't make sense in an expression, but perfect sense in a monad, so the if statements without an else is captured by the functions when and unless.

Another common case is doing list operation in a more general context. Functional languages are quite fond of fold, and the Specialized versions like map and filter. If you have a monad then there is a natural extension of fold to it. This is called foldM, and therefor there are also extensions of any specialized version of fold you can think of, like mapM and filterM.

Colloquial answered 27/11, 2010 at 23:4 Comment(0)
P
11

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

Passant answered 27/11, 2010 at 21:38 Comment(4)
I am actually pretty sure that macros + tail-calls + delimited continuations (+mutable state perhaps) indeed are the universal basis for all possible control structures. I think so because the Cont monad is the mother of everything :)Dayflower
This still leaves open the question of what control structures you would implement. Okay great, Lisp macros generalizes all of the control structures I need; okay great, maybe they shouldn't be in the core language. This still doesn't answer which specializations I choose. We have historically found that if and while can be useful -- what else?Misconstrue
@A. Rex: actually, I can't remember the last time I used a while loop outside of some kind of very special context. I believe the last time was in a hand-written recursive descent parser, where I used it more as a DSL element than an actual loop. I usually use maps, folds, catamorphisms, filters, transformers. I don't even use plain iterators that often. In a modern language, pretty much the only reason to use a while loop is when you want an infinite loop such as in the event loop of an operating system. But for that, you might just as well use a tail recursive function.Transudation
Nitpick: there is a paper floating around which proves that exceptions can be more powerful than continuations. (In fact, one of the common criticisms against exceptions is that they are just GOTO under a different name.) So, technically speaking continuations are a restricted version of try/catch. But this is hairsplitting of the worst kind :-) I fully understand what you mean. It can be useful, though: the Volta CIL->ECMAScript compiler uses exceptions to implement continuations and threads, for example.Transudation
C
11

This is just a general idea and syntax:

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end

ALSO condition is always evaluated. ELSE works as usual.

It works for case too. Probably it is a good way to eliminate break statement:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end

can be read as:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end

I don't know if this is useful or simple to read but it's an example.

Cobalt answered 28/11, 2010 at 11:33 Comment(0)
M
8

if not:

unless (condition) {
  // ...
}

while not:

until (condition) {
  // ...
}
Morphia answered 28/11, 2010 at 3:31 Comment(6)
It took me a while to get used to them (in Perl), but I do feel like I use them natively now.Misconstrue
Scala: def unless(cond: => Boolean)(f: => Unit) { if(!cond) f } and def until(cond: => Boolean)(f: => Unit) { while(!cond) f }. :DWere
I actually dislike them in Perl. I tried to use them, but found, that they obfuscate the code rather than make it clearer. Maybe it's because in other languages one usually doesn't use such constructs...Obliging
To clarify what I'm trying to say: in other languages one usually uses if (!..) and while (!..) instead, which makes them much more idomatic across languages.Obliging
I think these constructs can make the intent clearer: compare, e.g., while(!done) to until(done).Dumbarton
@Jordão, it's a subtle issue - I have to look once at if (!..), twice at unless (..), and a thousand times at the rest.Obliging
W
8

Labeled loops are something I find myself missing sometimes from mainstream languages. e.g.,

int i, j;
for outer ( i = 0; i < M; ++i )
    for ( j = 0; j < N; ++j )
        if ( l1[ i ] == l2[ j ] )
           break outer;

Yes, I can usually simulate this with a goto, but an equivalent for continue would require you to move the increment to the end of loop body after the label, hurting the readability. You can also do this by setting a flag in the inner loop and checking it at each iteration of the outer loop, but it always looks clumsy.

(Bonus: I'd sometimes like to have a redo to go along with continue and break. It would return to the start of the loop without evaluating the increment.)

Wallace answered 28/11, 2010 at 7:7 Comment(3)
You can also emulate multilevel break and continue with an exception. It isn't the most elegant of solutions. I did have to resort to it once. On the plus side, it does work even if the innermost loop has been extracted to another function.Corrody
For the record, JavaScript and Java both have this.Apery
+1 for redo. I find myself wanting this, especially when traversing and inserting/erasing only some times in a list. (In c++ that is, dunno if it can be done well in other )Settlement
V
8

I propose the "then" operator. It returns the left operand on the first iteration and the right operand on all other iterations:

var result = "";
foreach (var item in items) {
    result += "" then ", ";
    result += item;
}

in the first iteration it adds "" to the result in all others it adds ", ", so you get a string that contains each item separated by commas.

Vasquez answered 28/11, 2010 at 9:56 Comment(1)
What about a having a new block allowed anywhere inside of a for loop... maybe having an else... first { ... } else { result += ", "; }Apery
C
8
if (cond)
   //do something
else (cond)
   //do something
else (cond)
   //do something
first
   //do something
then
   //do something
else (cond)
   //do something
else
   //do something
end

FIRST and THEN blocks runs if any of 3 conditionals are evaluated to true. FIRST block runs before the conditional block and THEN runs after the conditional block has ran.

ELSE conditional or final write following FIRST and THEN statement are independent from these blocks.

It can read as :

if (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   //do something
else
   //do something
end


function first()
   //do something
return
function then()
   //do something
return

These functions are just a form to read. They wouldn't create scope. It's more like a gosub/return from Basic.

Usefulness and readability as matter of discussion.

Cobalt answered 28/11, 2010 at 12:25 Comment(0)
N
6

How about

alternate {
    statement 1,
    statement 2,
    [statement 3,...]
}

for cycling through the available statements on each successive pass.

Edit: trivial examples

table_row_color = alternate(RED, GREEN, BLUE);

player_color = alternate(color_list); // cycles through list items

alternate(
    led_on(),
    led_off()
);

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

alternate {
    led_on();
}
then {
    led_off();
}

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

Nummulite answered 28/11, 2010 at 3:17 Comment(6)
That's interesting. Can you give me an example use case?Misconstrue
How is this a control construct?Were
@missingfaktor: Because control changes after each time through "alternate()". If implemented as a function (in most languages) then led_on() and led_off() would be called before calling alternate. It could be emulated with lambdas and a non-local variable to hold state, but that's extra complication. On the other hand, this seems a rare need and not worth having specific syntax. After all, it's easy to implement something mostly like it in Python with itertools.cycle().Corrody
+1 for the thought. I think this might do what you suggest... def alternate(*args): while True: for arg in args: yield arg() itertools.cycle() is probably a library that does something similar, but this got me thinking more about generators and coroutines! Edit: formatting terribleKassab
You can accomplish this kind of thing using just functions with closures. In JavaScript for example, you could write this code: function cycle(choices) { var i = 0; return function() { var current = i; i = (i + 1) % choices.length; return choices[current]; }; } You could use this code like this: var colors = cycle(["blue", "white", "red"]); for (var i = 0; i < 5; ++i) alert(colors()); If you use Python, this function is already provided in itertools and if you use Haskell, you can find it in the Prelude.Immune
Clojure has such a function and since clojure sequences are lazy, you can use it to generate lists of any size. (I dont know the name of the function offhand, so I'll use alternate as an example): (take 4 (drop 1 (alternate :red :green :blue))) would generate the sequence [:green :blue :red :green]Klong
V
5

D's scope guards are a useful control structure that isn't seen very often.

Vasquez answered 28/11, 2010 at 9:43 Comment(1)
They're similar to "defer" in the Go language.Dayflower
N
5

I think I should mention CityScript (the scripting language of CityDesk) which has some really fancy looping constructs.

From the help file:

{$ forEach n var in (condition) sort-order $}
... text which appears for each item ....
{$ between $}
.. text which appears between each two items ....
{$ odd $}
.. text which appears for every other item, including the first ....
{$ even $}
.. text which appears for every other item, starting with the second ....
{$ else $}
.. text which appears if there are no items matching condition ....
{$ before $}
..text which appears before the loop, only if there are items matching condition
{$ after $}
..text which appears after the loop, only of there are items matching condition
{$ next $}
Nonperishable answered 3/12, 2010 at 13:10 Comment(0)
D
4

Also note that many control structures get a new meaning in monadic context, depending on the particular monad - look at mapM, filterM, whileM, sequence etc. in Haskell.

Dayflower answered 27/11, 2010 at 21:59 Comment(0)
W
4

ignoring - To ignore exceptions occuring in a certain block of code.

try {
  foo()
} catch {
  case ex: SomeException => /* ignore */
  case ex: SomeOtherException => /* ignore */
}

With an ignoring control construct, you could write it more concisely and more readably as:

ignoring(classOf[SomeException], classOf[SomeOtherException]) {
  foo()
}

[ Scala provides this (and many other Exception handling control constructs) in its standard library, in util.control package. ]

Were answered 28/11, 2010 at 3:57 Comment(3)
Ignoring an exception is normally akin to swallowing a bug. Which is not good for most applications.Dumbarton
@Jordão: There are cases where you might need to do that and in such cases, this control construct really makes code cleaner.Were
At the very least, the software should make note that it ignored a certain exception. It might also be a good idea to add some directive to the exception class that indicates it can be ignored, to prevent abusing this feature.Gerianne
W
4

Something that replaces

bool found = false;
for (int i = 0; i < N; i++) {
  if (hasProperty(A[i])) {
    found = true;
    DoSomething(A[i]);
    break;
  }
}
if (!found) {
  ...
}

like

for (int i = 0; i < N; i++) {
  if (hasProperty(A[i])) {
    DoSomething(A[i]);
    break;
  }
} ifnotinterrupted {
  ...
}

I always feel that there must be a better way than introducing a flag just to execute something after the last (regular) execution of the loop body. One could check !(i < N), but i is out of scope after the loop.

Warrington answered 3/12, 2010 at 0:29 Comment(3)
I really like something like "ifnotinterrupted".Misconstrue
Python has this: for and while have an (optional) else block that runs only if they complete "naturally" (i.e. without a break).Oday
@chpwn: Wow, seems that I misinterpreted else after loops in Python (I never used it); Thank you for telling me. However, I think "else" is a misnomer.Warrington
P
4

I'd like to see a keyword for grouping output. Instead of this:

        int lastValue = 0;

        foreach (var val in dataSource)
        {
            if (lastValue != val.CustomerID)
            {                    
                WriteFooter(lastValue);
                WriteHeader(val);
                lastValue = val.CustomerID;
            }
            WriteRow(val);
        }
        if (lastValue != 0)
        {
            WriteFooter(lastValue);
        }

how about something like this:

        foreach(var val in dataSource)
        groupon(val.CustomerID)
        {            
            startgroup
            {
                WriteHeader(val);
            }
            endgroup
            {
                WriteFooter(val)
            }
        }
        each
        {
            WriteRow(val);
        }

If you have a decent platform, controls, and/or reporting formatting you won't need to write this code. But it's amazing how often I find myself doing this. The most annoying part is the footer after the last iteration - it's hard to do this in a real life example without duplicating code.

Priestly answered 3/12, 2010 at 0:32 Comment(3)
+1 I missed this one some time ago when working in VB6. Also, ABAP has this.Dumbarton
Very interesting, this is the specialization I am thinking of. The At First and At Last for the entire iteration is a nice touch.Priestly
In Harbour you can use item:__enumIsFirst and item:__enumIsLast to return a boolean if you are at the first and last itemHorehound
A
3

This is a bit of a joke, but you can get the behavior you want like this:

#include <iostream>
#include <cstdlib>

int main (int argc, char *argv[])
{
  int N = std::strtol(argv[1], 0, 10); // Danger!
  int state = 0;
  switch (state%2) // Similar to Duff's device.
  {
    do {
      case 1: std::cout << (2*state) << " B" << std::endl;
      case 0: std::cout << (2*state+1) << " A" << std::endl; ++state;
    } while (state <= N);
      default: break;
  }

  return 0;
}

p.s. formatting this was a bit difficult and I'm definitely not happy with it; however, emacs does even worse. Anyone care to try vim?

Aimee answered 28/11, 2010 at 0:47 Comment(1)
This is not an answer to the OP question.Cobalt
O
3

Generators, in Python, are genuinely novel if you've mostly worked with non-functional languages. More generally: continuations, co-routines, lazy lists.

Overglaze answered 28/11, 2010 at 4:28 Comment(0)
G
3

This probably doesn't count, but in Python, I was upset there was no do loop.

Anto ensure I get no upvotes for this answer, I wind up annoyed at any language I work in for any period of time that lacks goto's.

Ganda answered 28/11, 2010 at 6:58 Comment(5)
There's a paper that proves that exceptions can be more powerful than continuations. Continuations are essentially equal in expressive power to GOTO. So, if your language has exceptions, it has GOTO.Transudation
@Jörg: Can you please post the link to the paper?Were
@missingfaktor: The title of the paper is [ Unchecked Exceptions can be Strictly More Powerful than Call/CC ](Lambda-the-Ultimate.Org/node/2966). Note that, as always with a scientific paper, one has to read very carefully what it actually is the paper proves. In this particular case, they show that adding SML-style exceptions to the Simply Typed λ-calculus (which is known not to be Turing-complete) makes it Turing-complete, whereas adding call/cc to System Fω (which is known to be a strict superset of STλC) doesn't. (The only way to make it TC breaks type soundness.)Transudation
This is not just academic trickery, BTW. I know of at least one compiler that used ECMAScript exceptions to implement other control-flow constructs: Microsoft Live Labs' Volta Project was (among other things) a compiler that compiled arbitrary CIL bytecode to ECMAScript source code. CIL (and more generally .NET and C#) has all sorts of control-flow ECMAScript doesn't: GOTO, coroutines, threads(!), all of which were implemented using ECMAScript exceptions.Transudation
Also note that: "Can be more powerful than" does not necessarily mean "can be used by a human". In particular, I believe that in order to use exceptions like GOTO you would have to rewrite your code in continuation-passing-style, then encode your continuation-passing-style into exceptions.Transudation
W
3
for int i := 0 [down]to UpperBound() [step 2]

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:

  1. UpperBound() is evaluated only once

  2. The case UpperBound() == MAX_INT does not produce an infinite loop

Warrington answered 3/12, 2010 at 0:8 Comment(0)
Q
2
foo();

while(condition)
{
   bar();
   foo();
}
Qadi answered 28/11, 2010 at 3:6 Comment(2)
This doesn't even do what his slit_while is supposed to do. And the real question is what new high level control structures you can think of, not how you could implement them.Vasquez
while (true) { foo(); if (!condition) break; Bar(); }Warrington
H
2

This is similar to the response by @Paul Keister.

(mumble, mumble) years ago, the application I was working on had lots of variations of so-called control-break processing -- all that logic that goes into breaking sorted rows of data into groups and subgroups with headers and footers. As the application was written in LISP, we had captured the common idioms in a macro called WITH-CONTROL-BREAKS. If I were to transpose that syntax into the ever-popular squiggly form, it might look something like this:

withControlBreaks (x, y, z : readSortedRecords()) {
  first (x) :     { emitHeader(x); subcount = 0; }
  first (x, y) :  { emitSubheader(x, y); zTotal = 0; }
  all (x, y, z) : { emitDetail(x, y, z); ztotal += z; }
  last (x, y) :   { emitSubfooter(x, y, zTotal); ++subCount; }
  last (x) :      { emitFooter(x, subcount); }
}

In this modern era, with widespread SQL, XQuery, LINQ and so on, this need does not seem to arise as much as it used to. But from time to time, I wish that I had that control structure at hand.

Hybridize answered 12/12, 2010 at 0:58 Comment(0)
B
1

How about PL/I style "for" loop ranges? The VB equivalent would be:

' Counts 1, 2, ... 49, 50, 23, 999, 998, ..., 991, 990
  For I = 1 to 50, 23, 999 to 990 Step -1

The most common usage I can see would be to have a loop run for a list of indices, and then throw in one more. BTW, a For-Each usage could also be handy:

' Bar1, Bar2, Bar3 are an IEnum(Wazoo); Boz is a Wazoo
  For Each Foo as Wazoo in Bar1, Bar2, Enumerable.One(Boz), Bar3

This would run the loop on all items in Bar1, all items in Bar2, Boz, and Bar3. Linq would probably allow this without too much difficulty, but intrinsic language support might be a little more efficient.

Blubbery answered 2/12, 2010 at 18:59 Comment(0)
L
1

One of the control structures that isn't available in many languages is the case-in type structure. Similar to a switch type structure, it allows you to have a neatly formatted list of possible options, but matches the first one that's true (rather then the first one that matches the input). A LISP of such such (which does have it):

(cond
   ((evenp a) a)        ;if a is even return a
   ((> a 7) (/ a 2))    ;else if a is bigger than 7 return a/2
   ((< a 5) (- a 1))    ;else if a is smaller than 5 return a-1
   (t 17))              ;else return 17

Or, for those that would prefer a more C-like format

cond 
    (a % 2 == 0): 
        a;     break;
    (a > 7):
        a / 2; break;
    (a < 5):
        a - 1; break;
    default:
        17;    break;

It's basically a more accurate representation of the if/elseif/elseif/else construct than a switch is, and it can come in extremely handing in expressing that logic in a clean, readable way.

Leannaleanne answered 14/11, 2011 at 21:56 Comment(0)
R
0

How about iterating with a moving window (of n elements instead of 1) through a list? This is tangentially related @munificent's answer, I think.

Something like

#python
#sum of adjacent elements
for x,y in pairs(list):
    print x + y

def pairs(l):              
    i=0                    
    while i < len(l)-1:    
        yield (l[i],l[i+1])
        i+=1               

It is useful for certain types of things. Don't get me wrong, this is easy to implement as a function, but I think a lot of people try to bring out for and while loops when there are more specific/descriptive tools for the job.

Revalue answered 6/6, 2012 at 17:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.