0

Sometimes I find it useful to have loops that do an action at the beginning and/or the end of a while loop.

The best way I can think of for representing this in C++ would be:

if(condition) {
    // Pre-loop actions.
    while(condition) {
        // Loop actions
    }
    // Post-loop actions.
}

Or with a goto optimization (theoretically):

if(condition) {
    // Pre-loop actions.
    goto loopStart;
    while(condition) {
            loopStart:
        // Loop actions
    }
    // Post-loop actions.
}

Do any programming languages had a more formal structure to represent this? Is this the best structural construction in C-like languages (e.g. has this been discussed in computer science literature)?

1

I'm not 100% sure I understand what sorts of things you are thinking of here. A more concrete realistic example might help.

But I personally find the example you gave in C++ already quite reasonable.

Please note also - there is a 'for loop' in C++, which comes very close to doing what you are describing.

From cppreference

for ( init-statement; condition(optional) ; iteration_expression(optional) ) statement

So you can write:

for (Pre-loop actions; condition; Post-loop actions) {
    // Loop actions
}

But here the pre-loop actions get done even if condition is false. And post-loop-actions get done every time through the loop.

There is another pattern I find VERY helpful, that you may be thinking of, and thats a 'finally' block. That nicely handles the cleanup after look logic.

For example see example use of Finally

        [[maybe_unused]] auto&& cleanup = Execution::Finally ([]() noexcept { ::endutxent (); });
        ::setutxent ();
        for (const utmpx* i = ::getutxent (); i != nullptr; i = ::getutxent ()) {
            if (i->ut_type == BOOT_TIME) {
                result.fBootedAt = DateTime (i->ut_tv);
                succeeded        = true;
            }
        }

here the 'finally' block is declared before the loop, but done afterwards (as going out of scope) - so useful for cleanup activities (especially in the presense of exceptions).

1

Since you already know the condition of the while loop is true when the loop is first encountered, you can change it to be a do/while loop:

if(condition) {
    // Pre-loop actions.
    do {
        // Loop actions
    } while(condition);
    // Post-loop actions.
}

That way the condition isn't checked again until after the loop has run once.

0

To write loops (other than those that iterate for a specific count), I use a third option, preferring the use of infinite loop with break; from somewhere in the loop:

// Pre-loop actions
for (;;) {
    // Pre-condition actions (e.g. prompt or prime)
    if ( ! condition ) 
        break;
    // post-condition actions (e.g. the main loop-body actions)
}
// Post-loop actions

This is about as DRY as you'll get.  Using a while often requires that the prompt/priming code is duplicated, e.g. once outside the loop and once in the loop.

Also, this approach doesn't duplicate testing of the condition.  I can imagine in some cases the whole loop needs to be done conditionally as you're suggesting; however, I would submit that the pre- and post-loop actions ideally would work ok even if the loop doesn't run any actual iterations; the less conditional logic, the better.

  • I can see this as being useful as long as the pre-loop actions and post-loop actions aren't absolutely dependent on the condition and are relatively inexpensive. The other argument besides (premature?) optimization for using a conditional followed closely by one-time loop initialization actions is it makes the pre-loop actions more explicitly part of the loop. But you correctly point out that condition is repeated, which may be problematic if condition is non-trivial. Of course if condition is nontrivial, one could make it into a lambda. – Graham Jul 31 '18 at 22:40
  • But also notable is that this approach can be done in lieu of gotos, even with the conditional wrapped around it. This sort of takes a variant do-while approach, which is a useful reminder. – Graham Jul 31 '18 at 23:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.