12

Similar question was closed on SO.

Sometimes when we're programming, we find that some particular control structure would be very useful to us, but is not directly available in our programming language.

What alternative control structures do you think are a useful way of organizing computation?

The goal here is to get new ways of thinking about structuring code, in order to improve chunking and reasoning.

You can create a wishful syntax/semantic not available now or cite a less known control structure on an existent programming language.

Answers should give ideas for a new programming language or enhancing an actual language.

Think of this as brainstorming, so post something you think is a crazy idea but it can be viable in some scenario.

It's about imperative programming.

Maniero
  • 10,826
  • 14
  • 80
  • 133
  • 2
    Why does this question have to be about "imperative programming"? – missingfaktor Nov 28 '10 at 17:14
  • 1
    @missingfaktor: Because control structures is about imperative programming. Sure, some problems can be solved with functional approach or another way but other paradigms doesn't put control structures on center of development. But anyway you can be creative. – Maniero Nov 28 '10 at 17:34
  • 3
    Well, I was going to share Pattern Matching with Guards, since those are more general that Case statements and If-Thens, but if this is a no FP zone, I guess that's just more Pattern Matching for the rest of us! – CodexArcanum Nov 29 '10 at 19:15
  • @CodexArcanum: Well, Pattern Matching is a construct very similar to imperative constructs. Indeed, Pattern Matching itself is an alternative to imperative control structures. Don't be shy ;-) – Maniero Nov 29 '10 at 21:31
  • Looking at all the answers makes me happy that none of the proposals exist in real life (and hopefully never will). Sorry :) – serg Dec 02 '10 at 23:15

22 Answers22

15

OK, this is a fun question.

I would also like to have a general else for while and for loops, for when the condition isn't true on the first test:

while (condition) {
    // process
}
else {
    // condition was never true
}

This avoids the awkward re-computation of the condition or storing it in a variable.

Macneil
  • 8,223
  • 4
  • 34
  • 68
  • Python has this. – Barry Brown Nov 28 '10 at 17:40
  • Hey! Finally a quirky choice of Python that I agree with! ;-) – Macneil Nov 28 '10 at 17:50
  • 5
    No. The else clause in Python for/while loops is executed if the loop ends normal, which means, the loop is not terminated through a break or return statement or an exception. In for loops the else clasuse is executed after the sequence of elements that is looped over is exhausted, and in while loops it is executed after the loop condition evaluates to False for the first time. – pillmuncher Nov 28 '10 at 18:33
  • 4
    There's [a request](http://bugs.php.net/bug.php?id=26411) to add the `while ... else` construct the way Macneil describes it to PHP. I think it's a great idea, because the "here are the results / there were no results" is a fairly common idiom in web apps. – Dean Harding Nov 28 '10 at 22:18
  • Maybe I'm misunderstanding... but why doesn't a do-while satisfy this situation? – Steven Evers Nov 29 '10 at 17:22
  • 2
    @SnOrfus: He wants a block of code (separate from the loop's block) that executes ONLY if the while condition is never met. Do-While executes the loop's block of code (not some separate block) once regardless of the while conditional. – Legion Nov 29 '10 at 18:39
  • 1
    In practice, this effect is easily achieved by setting a "flag" in the loop's code block, and then having an "if" conditional that follows the loop, which checks for the flag and executes a block of code if the flag's not set. But I do kind of like the while-else syntax idea. – Legion Nov 29 '10 at 18:40
  • @pillmuncher you are correct that Python's while...else isn't equivalent to the syntactic proposal made here, but it could implement it, if the programmer made sure to always `break` out of the main `while` body. – dubiousjim Oct 19 '12 at 14:56
10

Why not mash a few answers into one?

while (expr) {

    // Executed every iteration, unless first{} is present.
    // May be explicitly called rest{} if you like first{} to come first.

    // Blocks may return results, and consequently be used in expressions.
    return expr;

} first {

    // Executed only on the first iteration.

} pre {

    // Executed before every iteration.

} post {

    // Executed after every iteration.

} catch (oops) {

    // All blocks are implicitly try{}ed if followed by a catch{}.

} finally {

    // Executes after the block completes, regardless of exceptions.

} else {

    // Executed if the loop body or rest{} never executes.

} never {

    // Executes only when a client is present.

} drop (bad, worse), // Explicitly ignore certain exceptions.
  until (expr);      // Here, have a post-body condition, too.

An extensible, generalised flow-control construct syntax in an imperative language would be rather useful and entertaining. Until that shows up, guess I'll just use Lisp or something.

Jon Purdy
  • 20,437
  • 7
  • 63
  • 95
7

Control structures as functions.

I want for, if, else, while, etc to be functions, not special structures.

I want return, try/except and goto to be derivatives of continuations.

This of course has less to do with a particular control structure and more to do with how you see control structures in general, the meta of control structures.

dietbuddha
  • 8,677
  • 24
  • 36
  • 2
    Continuations are a heavyweight concept for a language, and there are good reasons for leaving them out of many languages. – David Thornley Nov 29 '10 at 19:23
  • I don't disagree; having `for`, `if`, `else`, and `while` as functions makes me infer that the parameters to those functions need to be lazily executed in order to behave the same as the original constructs. Having the ability to do lazy execution would be nice. – Dr. Wily's Apprentice Nov 29 '10 at 21:26
  • 1
    @David: Just because they are there doesn't mean you have to use them. Regular programmers can use what they are used to `return`, exceptions, etc. But now the expert programmer has a powerful additional tool in his toolbox if the need arises. Besides, IMHO languages shouldn't be "dumbed down". Languages should have the ability to support increased expertise and growth of CS knowledge. – dietbuddha Nov 30 '10 at 01:05
  • @dietbuddha: +1, but if you have `for` etc. as functions then you need lazy evaluation, which means you will have *space leaks* (which is *not* the same as a memory leak in languages with dynamic allocation). Typical scenario: a loop that iterates n times potentially requires O(n) stack space for thunks. Even experts have trouble telling whether a line of code contains a space leak. This is a class of bugs that simply does not occur with eager-evaluating languages. – j_random_hacker Nov 30 '10 at 06:49
  • @dietbuddha: Except that continuations have other consequences for the language and compiler. There has to be some sort of data structure that contains all the execution information at the moment, which is a lot easier for a language like Scheme than one like C, and ways to handle it. This may constrain other language features and optimizations (a long time ago I was in an argument about continuations for Common Lisp), and will take up implementation resources. Just having continuations in the language is a major effect. – David Thornley Nov 30 '10 at 14:55
  • 1
    @dietbuddha: (cont) I'm not saying continuations are bad, I'm saying they're heavyweight, and making them usable has implications for the language, something like exceptions do. Further, having continuations is likely to force changes in how people use the language, again like exceptions in C++. A language that supports continuations will be different from one that doesn't, in both good and bad ways. – David Thornley Nov 30 '10 at 15:02
  • @David - does that mean the C `longjmp` isn't a kind of continuation - I'm not familiar enough with either, but I *thought* they could achieve the same effect. –  Dec 02 '10 at 09:33
  • 1
    @Steve314 - longjmp is not a continuation although there are similarities. Continuations save the entire state (all locals, globals, and the stack). longjmp saves a stack _pointer_ so if you escape past the scope where setjmp was used you get a segfault since the frame no longer exists. I believe there are also some limitations in the variables it saves. – dietbuddha Dec 02 '10 at 17:40
  • @dietbuddha - if continuations save all locals, globals etc - does that mean that the code executed between saving the state and returning to it can have no side-effects on application data? –  Dec 04 '10 at 10:38
6

The linked article definitely gets it right about Donald Knuth's N+1/2 Loops. Expressed in C/C++/Java:

for (;;) {
  get next element;
  if (at the end) break;
  process the element;
}

This is useful for reading lines or characters from a file, testing if you've reached EOF, and then processing it. I'm so used to seeing the pattern for(;;)..if(..)break; appear that it's idiomatic to me. (Before I had read the Knuth article, reprinted in the book Literate Programming, this one used to be a "wtf?".)

Knuth suggested the keywords loop/while/repeat:

loop:
  S;
while C:
  T;
repeat

Where S and T are place holders for a series of zero or more statements, and C is a boolean condition. If there was no S statement then it would be a while loop, and if there was no T statement then it would be a do loop.

This construct itself could be generalized by allowing zero or more while C clauses, making it perfect for expressing infinite loops and then some rarer conditions that would need two checks.

In the same article, Knuth suggested a signaling mechanism that would be a local version of throwing/catching exceptions (as an alternative to using goto).

For me? I wish Java supported tail-call optimization, so that I could express any general control structure as needed.


Update: I forgot to mention that many C/C++/Java programmers get around this one by using an embedded assignment in the condition of the while:

while ((c = getc(f)) != -1) {
   T;
}

Using the terms from Knuth's construct, this is allowable when S and C can be combined into a single expression. Some people hate to see the embedded assignment above, while others hate to see the break in the for (;;) above. But when S and C cannot be combined, such as when S has multiple statements, the for (;;) is the only alternative without repeating code. The other alternative is to simply duplicate the S code:

S;
while (C) {
  T;
  S;
}

Knuth's loop/while/repeat alternative seems much better.

Macneil
  • 8,223
  • 4
  • 34
  • 68
  • That loop-while-repeat looks a whole lot like the Pascal `repeat-until` loop. – Mason Wheeler Nov 28 '10 at 16:44
  • @Mason: The difference is there are two places you can insert statements plus your condition, not just one. – Macneil Nov 28 '10 at 16:52
  • Oh, I see what's going on. Yeah, that's interesting... – Mason Wheeler Nov 28 '10 at 16:54
  • ANSI Basic had a `do while ... loop until` - both the precondition and postcondition are optional, and I (vaguely) remember using both in one loop. For your mid-condition, there's the Ada `exit when ...;`. The key advantage over `if ... break;` is that you can write `exit loopname when ...;` to exit out of multiple (but not necessarily all) nested loops at once. Probably slightly more visible than that break, too. –  Nov 28 '10 at 23:45
  • Funny thing. Ada has exactly that feature. – John R. Strohm Nov 29 '10 at 20:31
6
unless(condition) {
  // ...
}

does the same thing as:

if(!condition) {
  // ...
}

repeat {
  // ...
} until(condition)

does the same thing as:

do {
  // ...
} while(!condition)
missingfaktor
  • 3,906
  • 1
  • 24
  • 31
6

The BCPL language had a valueof expression that could be used to turn a sequence of statements into a single expression:

foo(a, b, valueof {some series of statements; resultis v});

Where some series of statements can be anything and the whole valueof evaluates to v.

This could be handy in Java for when you need to compute an argument for calling a this() or super() (which requires that nothing happen before it). Of course, you could just write a separate method, but that might be a pain if you need to pass in many local values for context.

If you are able to use final for variables that are needed, you can already do a valueof in Java using anonymous inner classes:

foo(a, b, new Object(){String valueof(){
    String v ...; some series of statements; return v;}}.valueof());
Macneil
  • 8,223
  • 4
  • 34
  • 68
  • 1
    GCC has an extension for this - `({ statement1; statement2; ...; result-expr; })`. I've seen similar elsewhere, too, but I don't remember where. Probably all copied from BCPL, though. –  Nov 29 '10 at 00:32
5

On a different note, I would like to see better support for iterators in programming languages. In particular, for when you want to go down two collections in pairs:

for (String s, Integer i : stringsSet, integersSet) {
    // use the pair (s, i)
}

Some dynamic languages may already have this, or easily support via libraries and macros, but I think this is in the spirit of your question.

If the two sets are not the same size, then it could throw an exception or you could have an else after the loop to signal there was a difference in sizes.

Naturally, you could generalize this for going down three or more lists.


Update: Also useful would be doing the Cartesian product between iterables:

for (String s, Integer i : stringsSet * integersSet) {
    // use the pair (s, i), each s with each i
}

which would be nothing more than nested loops:

for (String s : stringsSet) {
    for (Integer i : integersSet) {
        // use the pair (s, i), each s with each i
    }
}

I'm a little concerned that between the two notations I've provided here that there is a O(n) and O(n^2) difference in the number of pairs, with only the change of a single character.

Macneil
  • 8,223
  • 4
  • 34
  • 68
  • 2
    In Python there are zip and zip_longest that do this. – pillmuncher Nov 29 '10 at 00:51
  • Cool, maybe I'm underestimating Python and should give it a second look after many years. That reminds me, sometimes you want the Cartesian product too, the equivalent of nested for loops. – Macneil Nov 29 '10 at 01:21
  • 1
    Both these cases in Scala: http://paste.pocoo.org/show/297429/ – missingfaktor Nov 29 '10 at 02:58
  • @missingfaktor: Nice! Language design really is library design, and vice versa. – Macneil Nov 29 '10 at 03:34
  • 1
    In reference to Cartesian product: Again, Python has it. `for a, b, c in itertools.product(iter1, iter2, iter3):` gives you the Cartesian product lazily evaluated. What's that? You want permutations and combinations of a given iterator too? `itertools.permutations`, `itertools.combinations`. – aaronasterling Nov 29 '10 at 21:43
  • 1
    Haskell perspective: use "zipWith" for the first case and list comprehension or the List monad for the second. Like the Python/Scala exmaples, but more elegant. :) – LennyProgrammers Dec 02 '10 at 12:17
4

Icon-style expressions with built-in backtracking.

Python gets a lot of the Icon generator benefits - and does a better job of them in general, IMO. And in principle the backtracking was just a kind of exception throw, but it was the simplicity of expressions the rough equivalent of...

x = (a / b) else c;

to handle fail-cases like division by zero.

Where Icon went nuts - no boolean-returning comparison operators. The comparisons always either succeeded or triggered backtracking, and there was some other semantic issue which I'm now desperately trying to remember that... well, let's just say it's probably more repressed than forgotten.

I always thought they should have an if expression with no else part - if (condition, success-value) kind of thing, backtracking if the condition returns false - and drop the weird comparisons.

EDIT I remember - obvious really. A comparison with two arguments either succeeds or fails - it doesn't compute a new value to return. So when it succeeds, what does it return? Answer - one of the arguments. But if you write a > b, which is the logical argument to return - a or b? And what if you write b < a instead? I think it always returned the right argument, which makes as much sense as anything, but it still usually seemed like the wrong argument to me.

4

There is so-called "Dijkstra's Loop" (also called "Dijkstra's Guarded Loop"). It was defined in The Guarded Command Language (GCL). You can find some information about it syntax and semantic in the above Wikipedia article at the section 6 Repetition: do.

Nowadays I actually know one programming language which supports this control struture directly. It is Oberon-07 (PDF, 70 KB). And it supports "Dijkstra's Loop" in thу form of while statement. Take a look at section 9.6. While statements in the above PDF.

WHILE m > n DO m := m – n 
ELSIF n > m DO n := n – m 
END

P.S. This is copy of my SO answer.

Wildcat
  • 621
  • 3
  • 11
4

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.

Maniero
  • 10,826
  • 14
  • 80
  • 133
3

Continuation Passing Style comes to mind. Then, of course, you'd like to have Tail Call Optimization as well.

pillmuncher
  • 853
  • 1
  • 6
  • 7
  • 1
    Not a huge fan of this, and I don't believe it's really a "control structure" but rather a building block in functional languages and programming style. Node.js seems rather hooked on it though. – Josh K Nov 28 '10 at 21:58
  • 1
    Of course it's a control structure. It's just not one that comes with a keyword like 'if' or 'for', but as a pattern to structure control flow (hence, control structure). It's even used behind the scenes by many compilers. And it's not limited to FLs either. You need functions as First Class Objects though. – pillmuncher Nov 28 '10 at 22:25
  • 1
    You get tail call optimisation in C and C++ these days, but IMO it misses the point. The point is that it *is* an optimisation. In Scheme, a genuine tail call is obvious. In C++ especially, many things can mean your tail call isn't a tail call. And stack overflow means your app is broken. IMO, there should be something like a `goto return ...;` statement, making the intention to tail-call explicit, so if the compiler can't make it iterative it's an error. –  Nov 28 '10 at 23:33
  • @Steve314: That may be more complicated with mutual recursion, like Scheme's famous read-eval-print. I don't think the C/C++ compilers optimize those cases. Am I wrong? – Macneil Nov 29 '10 at 01:29
  • 1
    @Macneil - that I know of for certain, tail call optimisation is done in GCC, Clang and Visual C++. GCC has more sophisticated conversions from recursion to iteration, that can handle a number of cases that aren't tail recursion. But a lot can go wrong. Pass a pointer to a local variable in that tail call and the stack frame can't be eliminated, as the variable needs to be kept alive. In C++, local variable destructors will normally happen after the "tail" call returns, meaning it isn't a tail call at all. –  Nov 29 '10 at 09:07
  • Mutual recursion in itself isn't an issue, though - tail call elimination doesn't necessarily imply turning recursion to iteration - any (genuine) tail call is a candidate. Visual C++ (and probably others) will inline direct recursion to a certain depth, and *still* eliminate the tail recursion too. Clang is the new shiny front-end for LLVM, designed as a back-end for C-like language compilers. it was recently used as an alternative backend to the Glasgow Haskell compiler. Any back-end optimisation a functional language needs, LLVM apparently has. –  Nov 29 '10 at 09:22
  • CPS is a control structure is it directly affects the flow of control. – dietbuddha Nov 29 '10 at 16:57
  • ++ Yeah. Back in the 70s, backtrack programming was big in AI, and continuation-passing was the way to do it. When backtrack could be controlled (because it was easy to take exponential time) it was very useful. – Mike Dunlavey Nov 29 '10 at 20:36
  • @Steve314: I think focussing on optimization is not the real point. IMO, the whole point of control structures is permitting certain kinds of programs to be written more clearly with less source code, although at the same time, it requires the reader to learn something they might not have, yet. – Mike Dunlavey Nov 29 '10 at 20:41
  • Reluctant +1. Continual Pain Style is certainly a control structure, the most general one I know of. Like most extremely general things, it's a gigantic pain to use when you don't need that level of generality, but occasionally allows things that otherwise aren't possible (e.g. coroutines). – j_random_hacker Nov 30 '10 at 06:58
  • 1
    @Mike - that's my point. If you use a recursive coding style, without the tail call "optimisation" your code is potentially broken, since stack overflow is an error. In C++ it's an optimisation - for the compiler to do optimisations so you don't have to is fine, but you can't rely on them. If you want the freedom to write in recursive style, but don't want to have to worry about stack depth issues, tail call elimination isn't optimisation - it's a correctness issue. If recursion is the best way to code something, you should be able to do that - not have to worry about stack overflow. –  Nov 30 '10 at 09:41
  • @Steve314: IMHO explicit recursion is never the best way to code something that would be tail-recursive, because that is *exactly* the set of problems that can be coded with iteration, which is a less general construct and therefore easier to understand. I would advocate building the equivalent of a for-loop iteration construct if your language does not support it natively. Rule of thumb: Choose the least powerful solution to a problem to make your program simpler and more comprehensible. – j_random_hacker Nov 30 '10 at 13:36
  • @j_random_hacker - My kneejerk reaction is to use iteration. Some more theory oriented people have criticised me for that. Nevertheless, some problems are simpler and more readable in recursive style. The two are mathematically equivalent, so strictly neither is more powerful - but forcing iteration to do the work of recursion is more complex than just recursing. Basically, I agree with the rule of thumb, but rules of thumb are fallible - when they are clearly misleading you, flexibility works better than being a slave to the rulebook. –  Dec 01 '10 at 05:49
  • @j_random_hacker - BTW, what is this mystery language of yours that doesn't have a `for` loop? I've used a few in my time - assembler languages mainly - but you're certainly not talking about C or C++. –  Dec 01 '10 at 05:53
  • @Steve314: Haskell lacks a `for` loop, and I don't think Scheme has them either -- right? And what is this mystery tail-recursively-solvable problem that is more simply and readably written that way than using a `while` loop? ;) – j_random_hacker Dec 01 '10 at 12:44
  • @Steve314: Another advantage of *not* using tail-call optimisation for recursion is that it becomes easier to see a program's space complexity at a glance: every recursive call requires a new stack frame, and every `for`/`while` doesn't. – j_random_hacker Dec 01 '10 at 12:47
  • @steve314: Prolog has no for-loops. – pillmuncher Dec 01 '10 at 12:49
  • @pillmuncher - but in Prolog you really wouldn't want to roll your own either. It's meant to be declarative, not procedural. Not *quite* true (ordered semantics relative to predicate algebra, cut), but you still don't want a for loop. Good point though, and some other declarative languages include lex and yacc - no for loops in them either. –  Dec 02 '10 at 07:28
  • @j_random_hacker - Haskell and Scheme are functional languages - they are built to encourage recursion. Scheme certainly has iterative loops as libraries, though. Haskell doesn't, but some iterations don't work well in Haskell. Even for a while loop, the condition needs to be sensitive to side-effects in the loop body, so needs to be within the monad. This is awkward enough that when working in Haskell, you really need to reverse perspective - recursion is the natural default. This is another variation on the one-size-does-not-fit-all argument. –  Dec 02 '10 at 07:34
  • @j_random_hacker - if the recursive calls are optimised tail calls, the space complexity is exactly as it would be with an iterative solution. If the recursion can't be optimised away, converting to iteration needs an explicit stack - all you've done is move your space requirement from one place to another (e.g. CPU stack to heap). Very rarely in C this is a reason to use recursion - avoiding heap-fragmentation and memory locality issues by keeping the data on the CPU stack. And a red-black tree insert (or worse, delete) is fiddly enough *with* recursion - doing it iteratively would be nuts. –  Dec 02 '10 at 08:09
  • @Steve314: Maybe I wasn't clear, I know that tail recursion, when optimised, has the same space complexity as iteration. What I meant was that if the compiler never optimises tail recursion, then you know at a glance whether a recursive call incurs extra space -- the answer is always "yes". The advantage is better code readability. At the same time you haven't sacrificed any power since anything that you could have written with a tail-recursive call, you can still write using `for`/`while` -- which again has the advantage of making it explicit that no extra space is needed. – j_random_hacker Dec 03 '10 at 00:09
  • @j_random_hacker - the same at-a-glance argument applies if the tail-call elimination is explicitly demanded in the source code, and treated as a control structure in its own right instead of as an optimisation - which is what I suggested (much) earlier in these comments. Once you spot that a call is recursive, you *know* whether you should assume the extra space requirement. True, the optimisation may reduce your space requirement anyway, without being explicitly demanded, but that applies to many optimisations - the whole point of optimisation is to make things more efficient. –  Dec 04 '10 at 10:29
  • @j_random_hacker - in other words, this explicitly demanded tail-call elimination is just another way to spell out an iteration, or would be if it existed. Just as a `for` loop may be better than a `while` loop for some jobs, yet not for others, this would mostly be just another way to iterate, with the same rules about cost and complexity applying. –  Dec 04 '10 at 10:32
  • @Steve314: I reread your 1st and 3rd posts and I see your point now I think: danger only arises when tail-calls are unclear (e.g. C++ destructor semantics) or the optimisation is not mandated by the language (since then it might or might not be applied). In all other cases, it's just like a "regular" loop. I would still say that `for`/`while` is even more explicit and thus even clearer, but I certainly agree with you on this. – j_random_hacker Dec 05 '10 at 00:36
3

Seamless thread branching, it has syntax like a function, but executes in a separate thread and can't access data that has not initially been passed to it.

branch foo(data, to, be, processed){
    //code
    return [resulting, data]
}

When a branch is called it will immediately return a handle.

handle=foo(here, is, some, data)

The handle can be used to check if the task is done.

handle.finished() //True if the execution is complete

If the result is requested before the execution is complete the main thread will simply wait.

[result, storage]=handle.result()

This wouldn't cover the more advanced multithreading scenarios, but rather provide an easily accessible way of beginning to utilize multiple cores.

aaaaaaaaaaaa
  • 1,076
  • 6
  • 11
  • Have a look at Cilk, it's a very clean and simple extension of C: http://en.wikipedia.org/wiki/Cilk. I don't know if it has a `handle.finished()` test, but `spawn` and `sync` are all you need for 90% of parallel programming tasks. – j_random_hacker Nov 30 '10 at 07:29
3
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.

Maniero
  • 10,826
  • 14
  • 80
  • 133
2

I sometimes find myself writing a loop that needs to do something different during the first iteration. For example, displaying <th> tags instead of <td> tags.

I handle this situation with a boolean flag. Something like this:

first = true

while (some_condition)
    if (first)
        do_something
        first = false
    else
        do_something_else

It seems silly to check the value of first on every iteration when it's going to be false most of the time.

I'd like to have a looping option to specify a different loop body on the first iteration. There would be no need for a separate variable. The compiled code wouldn't need one, either, because the generated code would have two bodies, one for the first iteration and one for the rest.

Barry Brown
  • 4,095
  • 4
  • 25
  • 27
  • The SO question has a similar idea, but with a "then" operator to be used on values. That way, you probably don't have duplicated code. E.g. `print(out, first "" then "")` – Macneil Nov 28 '10 at 19:10
  • 1
    Better way is to either start the iteration +1. – Josh K Nov 28 '10 at 21:56
  • 1
    Common case is looping with between-handling, for example listing items with a comma separator. Strictly, that's `if (!first) gimme-a-comma ();`, but much the same thing. An objection I'd have, though - if you wrap it up appropriately you end up with things like the Python string join method - however often you need the basic pattern, the underlying loop needn't be rewritten that often. –  Nov 29 '10 at 00:12
  • As Josh says, of course, pulling the first item out of the loop is valid. In the comma-separator case it means duplicate code, but that can be a duplicated function call. Personally, I prefer the inefficiency of the `if (!first)`, but micro-optimisers may raise branch-prediction objections. –  Nov 29 '10 at 00:15
  • @Steve & @Josh: I think the idea here is that you want to better express your *intentions* in the code. It's not about avoiding flags so much as it's making special cases of the branch logic more clear. – Macneil Nov 29 '10 at 01:28
  • @Macneil: You can always add comments to indicate intention, but regardless of how much language based syntactical sugar there is, it's going to do the same thing under the hood. Create a temporary `bool` and flip it after the first iteration. Still going to check for it too. – Josh K Nov 29 '10 at 04:17
  • @Josh: OK, fair enough... the point of the question is to think about ways to better express your intentions in the code *using control structures*. The OP asks for brainstorming, so I'm curious why so many people are down voting on-topic answers. – Macneil Nov 29 '10 at 04:25
  • @Macneil: BEcause the downvoters don't like those answers perhaps? I'm trying to find a reason to close the question but can't find a good one. – Josh K Nov 29 '10 at 05:06
  • There's no need for an under-the-hood boolean flag. It can be done by "unrolling" the loop for the first iteration. ("Unrolling" in quotes because the first iteration will actually have a different body.) – Barry Brown Nov 29 '10 at 05:50
  • 1
    @Barry Brown: Unrolling the 1st iteration of the loop may or may not be faster than checking a boolean flag. A decent branch predictor will mispredict at worst the 1st 2 iterations, I predict :) I would prefer to use `if (!first)` and let an optimising compiler decide whether the loop body is small enough that unrolling and getting rid of `first` is a net win. – j_random_hacker Nov 30 '10 at 07:57
  • @j_random_hacker - the boolean version may be "unrolled" anyway. Optimisers analyse flow at that kind of level, and should know that the bool is true the first time through, false otherwise. They may even extract out the body into a function, to avoid the duplication for larger bodies. I don't know any of this, though - and don't really care. I agree with leaving it to the compiler. –  Dec 02 '10 at 08:58
1

[ copied from my own answer on stackoverflow ]


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

missingfaktor
  • 3,906
  • 1
  • 24
  • 31
  • 4
    Exceptions shouldn't be ignored. – Josh K Nov 28 '10 at 21:55
  • 1
    Except that, in context, an exception may not be an error. –  Nov 28 '10 at 23:36
  • 1
    @Josh, @Steve: There are cases when you would want to ignore the exceptions. See [this thread](http://programmers.stackexchange.com/questions/16807/is-it-ever-ok-to-have-an-empty-catch-statement) for some such cases. – missingfaktor Nov 29 '10 at 02:50
  • An exception is an alert that something may be wrong. An empty `try..catch` block is one thing; it forces you to recognize the error and deliberately ignore it; while throwing chunks of code under a global ignore can lead to issues when those exceptions are thrown, as well as lead to poor programming habits. – Josh K Nov 29 '10 at 02:53
  • @Josh - Just deleted two comments because I wasn't thinking straight - but hopes are high for this one. If that statement is global, I probably agree - but it looks like a block structure to me. IOW it's like a `try` block, except it lists the exceptions it catches and ignores up front, instead of later on. That could even be a readability advantage - e.g. letting the reader know that a missing file isn't an error even before they read the open call. –  Dec 02 '10 at 09:20
  • And the award for *"most likely to be abused language feature"* goes to! – MattDavey Jul 19 '12 at 16:59
1

Instead of:

switch(myEnum) {
  case MyEnum.Val1: do1(); ...
  case MyEnum.Val2: do2(); ...
....

Do it the Python, or now the C# way as well:

action = val2func[myEnum]
action()

Scala has lots of new features.

Finally, languages such as Clojure can be extended to provide the extra functionality.

Job
  • 6,459
  • 3
  • 32
  • 54
  • 1
    C can do this too. And Pascal. An probably all those old 70s/80s/90s languages. An array of functions becomes an array of function pointers, but that's no big deal. Where it gets easier is when you've got anonymous functions - you know, like in Lisp, ML, ... –  Dec 02 '10 at 09:39
  • Steve314 - correction - this is an example of a dictionary which maps any value to a function. This is where things become slightly cleaner than most things from 70s/80s/90s could do. – Job Dec 02 '10 at 22:12
1

I have two ideas.

Often I find that I am repeating myself in catch blocks. This can be somewhat helped through extracting methods, but that can cause unnecessary clutter if the methods are very short or otherwise not worthy of a method. So, it would be nice to nest catch blocks:

try {
    // Save something
} catch (Exception e) {
    // Something we do for all Exceptions
    catch (ProcessingException e) {
        // Something we do for all Processing exceptions
        catch (DBExcpetion e) {
            // DBExceptions are a subclass of ProcessingException
        }
        catch (BusinessRuleException e) {
            // BusinessRuleExceptions are also a subclass of ProcessingException
        }
    }
    // Something we do after specific sub class Exceptions
 }

In web programming I am also often find myself often doing something like this (this isn't a real example so don't analyze fictional cases):

Account a = getSavedAccount();
if (a == null) {
    a = getAccountFromSessionId();
}
if (a == null) {
    a = getAccountFromCookieId();
}
if (a == null) {
    a = createNewAccount();
}

In Javascript (well, ECMAScript, and maybe others that I am unfamiliar with), since any value can be evaluated as a condition, || can help.

var a = getAFromLocation1() || getAFromLocation2() || default;

I really like how that looks, and I wish more languages, particular some on the server side, had support for it. (PHP can evaluate anything as a condition, but converts the whole conditional expression to a boolean instead of preserving the value. I don't know about Python or Ruby.) It could get unwieldy after three cases or so, but if you have more than three cases, you might also have a bad software design.

Nicole
  • 28,111
  • 12
  • 95
  • 143
  • Python does something like your || evaluation, but when it finally got its conditional expression `x if c else y` syntax, a major reason that happened was because a lot of expressions using these semantics for `||` and `&&` were subtly buggy. IIRC a common case was a value (such as zero) that was valid for the application being treated as `false`, thus being discarded so that an invalid fallback was used instead. However - see my answer WRT the Icon programming language, which can have expressions like `get1() else get2() else default`. –  Dec 02 '10 at 09:49
1

Generalised switch has said above :

 switch(x){
  predicate1:
     dosomething();
  predicate2:
     dosomethingelse();
 }

In Haskell :

  switch' :: a -> [(a -> Bool, b)] -> b
  switch' a [] = undefined
  switch' a (f,b):xs = if f a
                     then b
                      else switch' a xs
0

In C# I would like to use simple switch () { ... }, but extendible with such expressions:

switch (value)
{
  // string-based operators:
  case begins "Maria": // to catch Maria Carey
    break;
  case ends "Washington": // to catch George Washington
    break;
  case like "ph": // to catch Phil, Phillip, Sophie
    break;
  case between "Aaron" and "April": // to catch all names between
    break;

  // use non-static variables in case expression:
  case Dao.GetDefaultBabyName():
    break;

  // continuable cases without breaking
  case "John":
    bonus = 25;
  case "Peter":
    salary = 500;
    break;

  // jumps between cases
  case "Aleron":
    // do something
    break;
  case "Bella":
    // do something
    jump "Aleron";
    break;

}

And so on. The same with numbers or other types (that supports IComparable, IConvertible, ...)

This might make my code more laconic and readable.

Genius
  • 581
  • 2
  • 7
  • Fall-through on cases is a known evil, and I'm generally ok without it. And jumps is too GOTOish for any sane programming. But having expressions and non-statics in the case would be a lovely addition. – CodexArcanum Nov 29 '10 at 22:35
0

It is a fun question, as @Macneil said.

My favorite unusual control structure, which I (humble cough) discovered, is differential execution.

It has certain uses. For me, the overwhelming use is in programming user interfaces, which is an instance of the more general problem of maintaining redundant data in correspondence. On the one hand, there is application data, and on the other, there are UI controls, that need to be kept in agreement. This sounds like "binding" but there's actually a lot more to it.

Usually I implement it by macros in C or C++. In C# I have to do it by hand-expanding statements. That is a pain, but it works.

Once I implemented it in terms of Lisp macros, and then it was very clean. It did not require carefulness on the part of the programmer. I could have done the same thing in any other structured language if I took the trouble to write a complete parser and then generate all the right stuff. That's a big project, and I haven't done it.

Mike Dunlavey
  • 12,815
  • 2
  • 35
  • 58
0

"Traditional" control structures like for are about controlling the working man, keeping him subservient to the corrupt ideologies of the ruling capitalist elite. That's why I use alternative control structures like ph0r instead. It's like for, but more radical: You won't catch ph0r wearing a suit and tie, spouting some corporate BS. ph0r keeps it real, man.

Fight the power!

j_random_hacker
  • 856
  • 7
  • 11
0

Simplest for loop-

for(100)
{
    //Will run for 100 times
}


for(i)
{
    //Will run for i times while i must be a positive integer
}


for(i as a)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 0 and 
    //scoped within the loop
}


for(i as a=2)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 2 and 
    //scoped within the loop
}
Gulshan
  • 9,402
  • 10
  • 58
  • 89