From -6491172512735092902
X-Google-Thread: 7894ca11fe,d47b345505a72a70
X-Google-Attributes: gid7894ca11fe,public,usenet
X-Google-NewGroupId: yes
X-Google-Language: ENGLISH,ASCII-7-bit
Path: g2news2.google.com!news1.google.com!newsfeed.stanford.edu!news.kjsl.com!news.alt.net!frodo.cs.rpi.edu!not-for-mail
From: "Alf P. Steinbach" <alfps@start.no>
Newsgroups: comp.std.c++
Subject: Re: for-else: adding else to for loops
Date: Sat,  8 Aug 2009 09:53:43 CST
Organization: A noiseless patient Spider
Lines: 141
Sender: cppmods@cs.rpi.edu
Approved: stephen.clamage@sun.com
Message-ID: <h5ie1s$bn8$1@news.eternal-september.org>
References: <5d82cd6c-2a22-4dd7-8c7d-790b579533ea@d15g2000prc.googlegroups.com>
NNTP-Posting-Host: netlab.cs.rpi.edu
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
To: (Usenet)
Return-Path: <cppmods@ruralroute.cs.rpi.edu>
X-Original-Date: Sat, 08 Aug 2009 01:32:43 +0200
X-Submission-Address: std-c++@netlab.cs.rpi.edu
Xref: g2news2.google.com comp.std.c++:1240

* Jared Grubb:
> I am both a Python and C++ developer, and there is one feature in
> Python that I've grown to appreciate, and that I wish C/C++ had. In
> Python, loops can have an else clause; the else clause gets executed
> when the loop condition fails (but not when the loop is exited via a
> break, return, or exception). For a dummy example:
> 
> auto iter = my_list.begin();
> for ( ; iter != lst.end(); ++iter)
> {
>      if (*iter == NEEDLE) break;
> }
> else
> {
>     cout << "needle not in the list";
> }

Oh my.

    struct Success {};
    auto iter = myList.begin();
    try
    {
        for( ; iter != myList.end();  ++iter )
        {
            if( *iter == needle ) { throw Success(); }
        }
        cout << "needle not in the list\n";
    }
    catch( Success const& ) {}
    cout << "tell me, did I just say something? or not?\n";

But, well, that sort of turns the usual meaning of an exception upside down.

So.

Perhaps :-) ...

    auto iter = myList.begin();
    for( ; iter != myList.end();  ++iter )
    {
        if( *iter == needle ) { goto later; }
    }
    cout << "needle not in the list\n";
    later:
    cout << "tell me, did I just say something? or not?\n";

But, wait, if I'm not mistaken that's a so called "goto". It's infamous for
allowing efficient and terse code. Can't have that, can we?

So...

    auto iter = myList.begin();
    for(
        ;
        (iter == myList.end()? (cout << "needle not in the list\n", 0) : 1);
        ++iter )
    {
        if( *iter == needle ) { break; }
    }
    cout << "tell me, did I just say something? or not?\n";

But again  --  it's not quite 100%...

For, the failure handling code can conceivably be unsuitable for being placed
inline in the loop head, yet not something that one would want to define a
separate routine for.

Therefore, combining two of the above approaches,

    struct LocalFailure { static bool x() { throw LocalFailure(); } };

    ...

    auto iter = myList.begin();
    try
    {
        for( ; (iter != myList.end() || LocalFailure::x()); ++iter )
        {
            if( *iter == needle ) { break; }
        }
    }
    catch( LocalFailure const& )
    {
        cout << "needle not in the list\n";
    }
    cout << "tell me, did I just say something? or not?\n";

This is so verbose and possibly inefficient, compared to the "goto", that no
doubt it will in a very short time be established as the idiomatic way to do
this thing. For what's "try" and "catch" /for/, if not for use for for loops?


> For a second example:
> 
> for (unsigned try = 0; try < MAX_TRIES; ++try)
> {
>      bool success = did_it_work();
>      if (success) break;
>      sleep(POLL_PERIOD);
> }
> else
> {
>      // Never worked
> }

Well, this sort of reminds of the oft repeated request for /multi-level/ 'break'.

It would break out of any labeled control construct, to following code.

E.g.

    // Example of Alf's preferred language extension for above problem.
    // Because it solves a lot more than just that problem.
    // And is very simple both syntactically and semantically.

    tryMaxTimes:
    {
        for( int t = 0; t < maxTries; ++t )
        {
            bool const success = didItWork();
            if( success ) { break tryMaxTimes; }  // <- Here. That's it.
            sleep( pollPeriod );
        }
        cout << "timeout, sorry\n";
    }
    cout << "tell me, did I just say something? or not?\n";

However, it may be too practical for standardization?


Cheers & hth.,

- Alf

-- 
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]



