Topic: for-else: adding else to for loops


Author: Ron <ron.natalie@gmail.com>
Date: Fri, 14 Aug 2009 12:44:50 CST
Raw View
On Aug 7, 1:56 pm, Jared Grubb <jared.gr...@gmail.com> wrote:
> 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:

In addition to the other points mentioned (breaking existing code),
the language
does not need any more horrendous structure violations.   The ones we
have existing
are sufficient.   Just because some other language likes to dish up
spaghetti is
no need to sully C++ further than it already is.



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





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sat, 15 Aug 2009 13:36:43 CST
Raw View
fw@deneb.enyo.de (Florian Weimer) wrote (abridged):
> > for (auto i : seq) {
> >      for one { cout << "The only number is " << i << '\n'; }
> >      for first { cout << "The numbers are " << i; }
> >      for last { cout << " and " << i << '\n'; }
> >      for others { cout << ", " << i; }
> > }
> > for none {cout << "There are no numbers\n";}
>
> Is this really necessary when you have lambda expressions in the
> language?

Good question. I would love to see this done with lambda expressions, as
a demonstration or test of what they, and C++0x, are capable of. (I don't
feel competent to do it myself.)

-- Dave Harris, Nottingham, UK.

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





Author: Hyman Rosen <hyrosen@mail.com>
Date: Sat, 15 Aug 2009 13:36:23 CST
Raw View
Ron wrote:
> the language does not need any more horrendous structure violations

The required code flow is the required code flow,
whether the language supports its expression directly
or not. Implementing the same flow by adding additional
boolean variables or repeating tests doesn't necessarily
improve the readability of the code.

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





Author: James Kanze <james.kanze@gmail.com>
Date: Sun, 16 Aug 2009 09:32:41 CST
Raw View
On Aug 15, 9:36 pm, Hyman Rosen <hyro...@mail.com> wrote:
> Ron wrote:
> > the language does not need any more horrendous structure
> > violations

> The required code flow is the required code flow, whether the
> language supports its expression directly or not. Implementing
> the same flow by adding additional boolean variables or
> repeating tests doesn't necessarily improve the readability of
> the code.

But throwing in an else without knowing what the "if" is
definitely destroys the readability.  You repeat the test or use
the added boolean variable so that the reader can see what the
test is---otherwise, he's fully in the dark.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: "Balog Pal" <pasa@lib.hu>
Date: Mon, 17 Aug 2009 13:18:00 CST
Raw View
"James Kanze" <james.kanze@gmail.com>
>> > the language does not need any more horrendous structure
>> > violations
>
>> The required code flow is the required code flow, whether the
>> language supports its expression directly or not. Implementing
>> the same flow by adding additional boolean variables or
>> repeating tests doesn't necessarily improve the readability of
>> the code.
>
> But throwing in an else without knowing what the "if" is
> definitely destroys the readability.  You repeat the test or use
> the added boolean variable so that the reader can see what the
> test is---otherwise, he's fully in the dark.

In the OP it was pretty clear what the "if" is, and when that branch is
called.
I second, that such cases come up in life, and that a native supporting
syntax would be ways better than any of the alternatives with available
tools.    And of the methods, using booleans and assignment is the only
surefire way, that makes the most mess of the code -- while the other alts
are prone to bugs like race condition, that is easy to miss.

With the else keyword it will not work, for the problems pointed out
upstream. Suppose we had a different keyword, 'forelse'.

for(; cond() ;++i)
{
   DoCycle();
}
forelse
{
   NothingDone();
}

Gurus could tell whether grammar would allow using a series of keywords,
say
'for else' at the spot without problems -- technical or human.



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





Author: Hyman Rosen <hyrosen@mail.com>
Date: Mon, 17 Aug 2009 13:18:48 CST
Raw View
James Kanze wrote:
> But throwing in an else without knowing what the "if" is
> definitely destroys the readability.  You repeat the test or use
> the added boolean variable so that the reader can see what the
> test is---otherwise, he's fully in the dark.

A language construct has a defined meaning. Why would a
reader be in the dark about it? My suggestion to augment
loops was
      for (init; test; next) SL or SO and SA
      while (test) SL or SO and SA
      do SL while(test); and SA
where a missing 'or' or 'and' part is taken to be there
with a null statement. SO is executed if 'test' is false
the first time it is evaluated. SA is executed if 'test'
is ever false when evaluated. A 'break' in SL, SO, or SA
moves control past the entire construct. Variables in the
'init' statement are in scope in SO and SA. Because of the
semantics of the 'or' and 'and' parts, execution of SO
falls into execution of SA, which is a nice touch.

This cleanly distinguishes between loops having empty
ranges, loops exhausting their ranges, and loops exited
early. What's dark about it?

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





Author: Helmut Zeisel <zei2006q1@liwest.at>
Date: Tue, 18 Aug 2009 12:56:09 CST
Raw View
On Aug 7, 7:56 pm, Jared Grubb <jared.gr...@gmail.com> wrote:

> I've seen examples
> in live code where developers solve this by:
> 1) re-testing the loop condition,
> 2) using an extra flag-variable declared outside of the for loop that
> can be tested after the for loop finished (e.g., put "bool
> success=false" outside the loop in the second example),
> 3) by encapsulating the for-loop in a separate function (the "break"
> becomes "return" and the extra code follows the for loop).

Why don't you use "goto after-else-branch" instead of "break"?

Helmut


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





Author: James Kanze <james.kanze@gmail.com>
Date: Tue, 18 Aug 2009 12:55:50 CST
Raw View
On Aug 17, 9:18 pm, "Balog Pal" <p...@lib.hu> wrote:
> "James Kanze" <james.ka...@gmail.com>

> >> > the language does not need any more horrendous structure
> >> > violations

> >> The required code flow is the required code flow, whether
> >> the language supports its expression directly or not.
> >> Implementing the same flow by adding additional boolean
> >> variables or repeating tests doesn't necessarily improve
> >> the readability of the code.

> > But throwing in an else without knowing what the "if" is
> > definitely destroys the readability.  You repeat the test or
> > use the added boolean variable so that the reader can see
> > what the test is---otherwise, he's fully in the dark.

> In the OP it was pretty clear what the "if" is, and when that
> branch is called.

It certainly wasn't to me.

> I second, that such cases come up in life, and that a native
> supporting syntax would be ways better than any of the
> alternatives with available tools.

A native supporting syntax for what?  I haven't yet figured out
what the OP wants (except maybe another tool for obfuscation).

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: Hyman Rosen <hyrosen@mail.com>
Date: Wed, 19 Aug 2009 20:45:11 CST
Raw View
James Kanze wrote:
>
> A native supporting syntax for what?  I haven't yet figured out
> what the OP wants (except maybe another tool for obfuscation).

Providing control flow after loop exit which distinguishes
between the loop having exited because its test condition
was false and the loop having exited through a break (and
in my syntax, also for the loop never having been executed).

Without special syntax, you wind up with additional boolean
variables or with repeated tests or with deeply indented code.

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





Author: "Joe Smith" <unknown_kev_cat@hotmail.com>
Date: Wed, 19 Aug 2009 23:12:24 CST
Raw View
"Jared Grubb" <jared.grubb@gmail.com> wrote:
> 3) by encapsulating the for-loop in a separate function (the "break"
> becomes "return" and the extra code follows the for loop).
>
> The third solution is probably the best way
> to do it, but sometimes encapsulating the for-loop out is not easy or
> nice.
>

With the ability to have (logically) nested functions due to lambdas

Could you not just do

auto iter=lst.begin();
[&]->void {
for (; iter != lst.end(); ++iter)
{
     if (*iter == NEEDLE) return;
}
cout << "needle not in the list";
}();

right where you would have otherwise put the code?



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





Author: Daphne Pfister <aw9jxzk02@sneakemail.com>
Date: Sat, 22 Aug 2009 12:37:18 CST
Raw View
On 2009-08-17 09:18:48 -0400, Hyman Rosen <hyrosen@mail.com> said:

> A language construct has a defined meaning. Why would a
> reader be in the dark about it? My suggestion to augment
> loops was
>       for (init; test; next) SL or SO and SA
>       while (test) SL or SO and SA
>       do SL while(test); and SA
> where a missing 'or' or 'and' part is taken to be there
> with a null statement. SO is executed if 'test' is false
> the first time it is evaluated. SA is executed if 'test'
> is ever false when evaluated. A 'break' in SL, SO, or SA
> moves control past the entire construct. Variables in the
> 'init' statement are in scope in SO and SA. Because of the
> semantics of the 'or' and 'and' parts, execution of SO
> falls into execution of SA, which is a nice touch.

Sounds almost like a switch... why not something like?

switch while (test)
{
case 1:
   // some code
   break; // exit the loop

case 2:
   // some code
   // fall though to next case

case 3:
   // some code
   continue; // go back to the top of the loop

default:
   // some code
   // fall through, and since last case would exit loop
}


Likewise with for:

switch for( init; test; next ) SL

Not only do they allow for something akin to original
suggestion they can simplify some scanning loop flows.
In particular it eliminates having to worry about adding
a done bool to handle a common case of having a switch
directly inside a for/while loop.

For
example:

// Skip whitespace but keep track of line numbers
char* c_str_ptr = ...;
int line_num = 0;
switch for ( ; *c_str_ptr; ++c_str_ptr )
{
   case '\n':
     ++line_num;
   case ' ':
   case '\t':
     continue;

   case 0:
     // end of string reached before non-white space
     // do something fancy if desired
     break;

   // This default does not really need to be here.
   // For exhibition only
   default:
     // non-white found
     break;
}

Combine with support for "case if (test):" and you have even
more power.

switch for ( auto my_iter = x.begin(); *my_iter; ++my_iter )
{
   case if ( my_iter == x.end() ):
     // Note *my_iter would not have been evaluated yet
     // since only cases seen so far are case ifs.
     std::cout << "Needle not found" << std::endl;
     break;

   case NEEDLE1:
     std::cout << "Needle1 found" << std::endl;
     break;

   case NEEDLE2:
     std::cout << "Needle2 found" << std::endl;
     break;

   default:
     continue;
}

My thoughts on case if would be that the switch test would
not be evaluated until the first case constant: or default:
(including the implicit default: at the bottom of a switch
if not present) was seen. And any case if would only be
evaluated if none of the cases before matched. Compilers
would still be able to take emit jump tables, but would have
to split them for crossing an "case if" boundary.

This would mean that the form

switch for( auto i : seq )
{
   // ...
}

Could be the same as

switch for( auto i = begin( seq ); *i; ++i )
{
   case if ( i == end( seq ) ):
     break;

   // ...
}

I'm aware that this suggestion does not completely cover the
"or SO" case of Hyman Rosen's suggestion.

Daphne Pfister



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





Author: ymett <ymett.on.usenet@gmail.com>
Date: Thu, 27 Aug 2009 16:45:55 CST
Raw View
On Aug 15, 10:36 pm, brang...@cix.co.uk (Dave Harris) wrote:
> f...@deneb.enyo.de (Florian Weimer) wrote (abridged):
>
> > > for (auto i : seq) {
> > >      for one { cout << "The only number is " << i << '\n'; }
> > >      for first { cout << "The numbers are " << i; }
> > >      for last { cout << " and " << i << '\n'; }
> > >      for others { cout << ", " << i; }
> > > }
> > > for none {cout << "There are no numbers\n";}
>
> > Is this really necessary when you have lambda expressions in the
> > language?
>
> Good question. I would love to see this done with lambda expressions, as
> a demonstration or test of what they, and C++0x, are capable of. (I don't
> feel competent to do it myself.)

template<class Range,
   class One, class First, class Last, class Other, class None>
void for_(Range&& range,
   One one, First first, Last last, Other other, None none)
{
   auto next = begin(range);
   if (next == end(range))
   {
     none();
     return;
   }
   auto current = next;
   ++next;
   if (next == end(range))
   {
     one(*current);
     return;
   }
   first(*current);
   while (current = next, ++next, next != end(range))
     other(*current);
   last(*current);
}

To be used as follows:

for_(seq,
      [](int i){ cout << "The only number is " << i << '\n'; },
      [](int i){ cout << "The numbers are " << i; },
      [](int i){ cout << " and " << i << '\n'; },
      [](int i){ cout << ", " << i; },
      []{cout << "There are no numbers\n";}
);

Some wrapper classes might make it look a little nicer:

template<class F> struct for_one_t { F f; };
template<class F> for_one_t<F> for_one(F f)
{ return for_one_t{f}; }

and likewise for for_first, for_last, for_others, and for_none.

Change the declaration to:

template<class Range,
   class One, class First, class Last, class Other, class None>
void for_(Range&& range, for_one_t<One> one,
   for_first_t<First> first, for_last_t<Last> last,
   for_others_t<Other> other, for_none_t<None> none);

(with appropriate changes to the definition) and you can write:

for_(seq,
   for_one([](int i){ cout << "The only number is " << i << '\n'; }),
   for_first([](int i){ cout << "The numbers are " << i; }),
   for_last([](int i){ cout << " and " << i << '\n'; }),
   for_others([](int i){ cout << ", " << i; }),
   for_none([]{cout << "There are no numbers\n";})
);

If you want to be able to omit some parts or to repeat some parts
that'll take a little more work (starting with defining exactly which
parts can appear where).

Unfortunately you have to repeat the element type (no auto available
there). Anyone for polymorphic lambdas?

Perhaps:

int i;
for_(i, seq,
   for_one([&]{ cout << "The only number is " << i << '\n'; }),
   for_first([&]{ cout << "The numbers are " << i; }),
   for_last([&]{ cout << " and " << i << '\n'; }),
   for_others([&]{ cout << ", " << i; }),
   for_none([]{cout << "There are no numbers\n";})
);

Implementation is left as an exercise for the reader.

Yechezkel Mett


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





Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Fri, 7 Aug 2009 16:24:23 CST
Raw View
On Aug 7, 1:56 pm, Jared Grubb <jared.gr...@gmail.com> wrote:
> 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";
>
> }
>
> 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
>
> }
>
> Being able to insert some code that runs when the loop condition is
> false can be useful, even if it is somewhat rare. I've seen examples
> in live code where developers solve this by:
> 1) re-testing the loop condition,
> 2) using an extra flag-variable declared outside of the for loop that
> can be tested after the for loop finished (e.g., put "bool
> success=false" outside the loop in the second example),
> 3) by encapsulating the for-loop in a separate function (the "break"
> becomes "return" and the extra code follows the for loop).
>
> The first two solutions result in code that is not as readable and
> even awkward (once you know how "for-else" works -- it's a little
> strange at first glance). The third solution is probably the best way
> to do it, but sometimes encapsulating the for-loop out is not easy or
> nice.
>
> I tried to find if this has ever been discussed, and I haven't been
> able to find any previous discussion on this construct. So, I was
> curious if anyone else had an opinion on whether this kind of
> construct would be useful.

Yes, I think this (and more) would be useful as well.  However I do
not expect to see it in C++0x.  Here is the syntax/functionality I've
toyed with:

for (auto i : seq)
{
   cout << ", " << i;
   for one   {cout << "The only number is " << i << '\n';}
   for first {cout << "The numbers are " << i;}
   for last  {cout << " and " << i << '\n';}
}
for none {cout << "There are no numbers\n";}

Example outputs:

{}:
There are no numbers

{0}
The only number is 0

{0, 1}
The numbers are 0 and 1

{0, 1, 2}
The numbers are 0, 1 and 2

{0, 1, 2, 3}
The numbers are 0, 1, 2 and 3

-Howard


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





Author: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 7 Aug 2009 18:20:24 CST
Raw View
jared.grubb@gmail.com (Jared Grubb) wrote (abridged):
> 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).

As it happens, a similar suggestion was made in this group on the 30th
June, by Doug Van Natter. It was pointed out then that the proposed
syntax would break existing code that preceded the for-loop with an
if-statement.

In any case, I don't think there is much support for extending the
control constructs, as we've managed to get on so well for so long
without them. You point out yourself three ways to write the code. A
goto-statement will sometimes work too. So the benefit is marginal, and
strictly a "programming in the small" affair.

Finally, you may find that closures enable you to encapsulate unusual
control situations in libraries.

-- Dave Harris, Nottingham, UK.

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





Author: Mathias Gaunard <loufoque@gmail.com>
Date: Sat, 8 Aug 2009 09:54:47 CST
Raw View
On 8 ao   t, 00:24, Howard Hinnant <howard.hinn...@gmail.com> wrote:

> for (auto i : seq)
> {
>    cout << ", " << i;
>    for one   {cout << "The only number is " << i << '\n';}
>    for first {cout << "The numbers are " << i;}
>    for last  {cout << " and " << i << '\n';}}
>
> for none {cout << "There are no numbers\n";}

I would have expected cout << ", " << i to be executed in all cases
here, not only in the non-one, non-first and non-last cases.


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





Author: "Alf P. Steinbach" <alfps@start.no>
Date: Sat, 8 Aug 2009 09:53:43 CST
Raw View
* 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                      ]





Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Sat, 8 Aug 2009 21:00:40 CST
Raw View
On Aug 8, 11:54 am, Mathias Gaunard <loufo...@gmail.com> wrote:
> On 8 ao   t, 00:24, Howard Hinnant <howard.hinn...@gmail.com> wrote:
>
> > for (auto i : seq)
> > {
> >    cout << ", " << i;
> >    for one   {cout << "The only number is " << i << '\n';}
> >    for first {cout << "The numbers are " << i;}
> >    for last  {cout << " and " << i << '\n';}}
>
> > for none {cout << "There are no numbers\n";}
>
> I would have expected cout << ", " << i to be executed in all cases
> here, not only in the non-one, non-first and non-last cases.

What would the use case look like?

-Howard



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





Author: darkmx <micael.dark@gmail.com>
Date: Sun, 9 Aug 2009 09:51:09 CST
Raw View
On 8 ago, 22:00, Howard Hinnant <howard.hinn...@gmail.com> wrote:
> On Aug 8, 11:54 am, Mathias Gaunard <loufo...@gmail.com> wrote:
>
> > On 8 ao   t, 00:24, Howard Hinnant <howard.hinn...@gmail.com> wrote:
>
> > > for (auto i : seq)
> > > {
> > >    cout << ", " << i;
> > >    for one   {cout << "The only number is " << i << '\n';}
> > >    for first {cout << "The numbers are " << i;}
> > >    for last  {cout << " and " << i << '\n';}}
>
> > > for none {cout << "There are no numbers\n";}
>
> > I would have expected cout << ", " << i to be executed in all cases
> > here, not only in the non-one, non-first and non-last cases.
>
> What would the use case look like?
>
> -Howard
>
> --
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ:http://www.comeaucomputing.com/csc/faq.html                     ]

it's not a matter of a use case, but a matter of syntax, I agree with
Mathias

I would prefer

for (auto i : seq) {
     for one { cout << "The only number is " << i << '\n'; }
     for first { cout << "The numbers are " << i; }
     for last { cout << " and " << i << '\n'; }
     for others { cout << ", " << i; }
}
for none {cout << "There are no numbers\n";}

and a naked cout << ", " << i; being executed every iteration


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





Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Mon, 10 Aug 2009 00:53:51 CST
Raw View
-----  O V E R Q U O T E D  -----

On Aug 9, 11:51 am, darkmx <micael.d...@gmail.com> wrote:
> On 8 ago, 22:00, Howard Hinnant <howard.hinn...@gmail.com> wrote:
>
> > On Aug 8, 11:54 am, Mathias Gaunard <loufo...@gmail.com> wrote:
>
> > > On 8 ao   t, 00:24, Howard Hinnant <howard.hinn...@gmail.com> wrote:
>
> > > > for (auto i : seq)
> > > > {
> > > >    cout << ", " << i;
> > > >    for one   {cout << "The only number is " << i << '\n';}
> > > >    for first {cout << "The numbers are " << i;}
> > > >    for last  {cout << " and " << i << '\n';}}
>
> > > > for none {cout << "There are no numbers\n";}
>
> > > I would have expected cout << ", " << i to be executed in all cases
> > > here, not only in the non-one, non-first and non-last cases.
>
> > What would the use case look like?
>
> > -Howard
>
> > --
> > [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> > [ your news-reader.  If that fails, use mailto:std-...@netlab.cs.rpi.edu]
> > [              --- Please see the FAQ before posting. ---               ]
> > [ FAQ:http://www.comeaucomputing.com/csc/faq.html                    ]
>
> it's not a matter of a use case, but a matter of syntax, I agree with
> Mathias
>
> I would prefer
>
> for (auto i : seq) {
>      for one { cout << "The only number is " << i << '\n'; }
>      for first { cout << "The numbers are " << i; }
>      for last { cout << " and " << i << '\n'; }
>      for others { cout << ", " << i; }}
>
> for none {cout << "There are no numbers\n";}
>
> and a naked cout << ", " << i; being executed every iteration

I see, thanks for the clarification.

-Howard


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





Author: Florian Weimer <fw@deneb.enyo.de>
Date: Mon, 10 Aug 2009 00:51:02 CST
Raw View
* darkmx:

> I would prefer
>
> for (auto i : seq) {
>      for one { cout << "The only number is " << i << '\n'; }
>      for first { cout << "The numbers are " << i; }
>      for last { cout << " and " << i << '\n'; }
>      for others { cout << ", " << i; }
> }
> for none {cout << "There are no numbers\n";}

Is this really necessary when you have lambda expressions in the
language?  It's slightly more verbose, but it's straightforward to
emulate this programming style.  (Handling break/continue poses
difficulties, of course, but it's not really clear what their
semantics would be anyway.)

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





Author: Jared Grubb <jared.grubb@gmail.com>
Date: Tue, 11 Aug 2009 14:06:10 CST
Raw View
On Aug 7, 5:20 pm, brang...@cix.co.uk (Dave Harris) wrote:
> jared.gr...@gmail.com (Jared Grubb) wrote (abridged):
>
> > 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).
>
> As it happens, a similar suggestion was made in this group on the 30th
> June, by Doug Van Natter. It was pointed out then that the proposed
> syntax would break existing code that preceded the for-loop with an
> if-statement.

Thanks for the pointer. I figured someone would have asked before, but
it's one of those things that are hard to construct a search for
("for" and "else" being such common words).

> In any case, I don't think there is much support for extending the
> control constructs, as we've managed to get on so well for so long
> without them. You point out yourself three ways to write the code. A
> goto-statement will sometimes work too. So the benefit is marginal, and
> strictly a "programming in the small" affair.

Ah, that's a good point and not easily solvable. It is a rare control
flow, but the alternatives are much harder to read -- and it's not a
hard flow to squeeze into the assembly (but neither is multiple-level
break, as someone else pointed out).

I just thought I'd ask. Once you've seen the flow, it's hard to get
out of your head when a use for it pops up!

Jared


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





Author: Hakusa <Hakusa@gmail.com>
Date: Wed, 12 Aug 2009 01:53:54 CST
Raw View
On Aug 9, 11:51 am, darkmx <micael.d...@gmail.com> wrote:

> it's not a matter of a use case, but a matter of syntax, I agree with
> Mathias
>
> I would prefer
>
> for (auto i : seq) {
>      for one { cout << "The only number is " << i << '\n'; }
>      for first { cout << "The numbers are " << i; }
>      for last { cout << " and " << i << '\n'; }
>      for others { cout << ", " << i; }}
>
> for none {cout << "There are no numbers\n";}

A few problems i'd like clarification on:
Wouldn't this require the reservation of one first last others and
none? Or would they become contextual words (which i think would be
confusing).

for others seems redundant. That could just be a normal block.

I'm thinking the pseudo code for for last might look like this:
 auto it = i;
 if( ++it == seq.end() )
     // do block
and that means input iterators couldn't have a for last?

Honestly, to circumvent this kind of problem, i sometimes use an if
mixed with a do while.

if( i != end ) {
   on_first();
   do some_func( *(i++) );
   while( i != end );
   on_last();
} else {
  oh_noes();
}

I've written prettier code, and it's a little more complex when you
put in the for first, for last, etc equivalents, but it works. I don't
like the new for loop anyway.


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





Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Wed, 12 Aug 2009 11:56:15 CST
Raw View
On Aug 12, 3:53 am, Hakusa <Hak...@gmail.com> wrote:
> On Aug 9, 11:51 am, darkmx <micael.d...@gmail.com> wrote:
>
> > for (auto i : seq) {
> >      for one { cout << "The only number is " << i << '\n'; }
> >      for first { cout << "The numbers are " << i; }
> >      for last { cout << " and " << i << '\n'; }
> >      for others { cout << ", " << i; }}
>
> > for none {cout << "There are no numbers\n";}
>
> Wouldn't this require the reservation of one first last others and
> none? Or would they become contextual words (which i think would be
> confusing).

I would think these would have to be contextual keywords.  And I've
been told contextual keywords are not going to happen in C++ (ever).
Another possibility would be to create new keywords such as for_one.

> I'm thinking the pseudo code for for last might look like this:
>  auto it = i;
>  if( ++it == seq.end() )
>      // do block
> and that means input iterators couldn't have a for last?

Input iterators could not be used with "for one", nor "for last".
Both of these require that one knows the end of the sequence is about
to happen, but hasn't happened yet.

> Honestly, to circumvent this kind of problem, i sometimes use an if
> mixed with a do while.
>
> if( i != end ) {
>    on_first();
>    do some_func( *(i++) );
>    while( i != end );
>    on_last();
>
> } else {
>   oh_noes();
> }
>
> I've written prettier code, and it's a little more complex when you
> put in the for first, for last, etc equivalents, but it works. I don't
> like the new for loop anyway.

Without the existence of the "for each" syntax I see no motivation for
this at all.  With "for each" I can see the motivation.  The whole
idea of "for each" is to remove the possibility of introducing
iteration errors for common loops.  Needing to special case loops of
length 0, 1, the first element, and/or the last element are arguably
sufficiently common as to warrant treatment within this context (not
that it should be done for C++0x, it should not -- maybe next time).

-Howard


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





Author: Hyman Rosen <hyrosen@mail.com>
Date: Wed, 12 Aug 2009 13:49:39 CST
Raw View
Jared Grubb wrote:

    I just thought I'd ask. Once you've seen the flow, it's hard to get
    out of your head when a use for it pops up!


How about this variant?

   for (auto i = c.begin(); i != c.end(); ++i)
       if (condition(*i))
           break;
   and
       // do this only if loop exited normally
       cout << "Condition never matched" << endl;
   or
       // do this only if loop never executed
       cout << "Empty container" << endl;

For an empty container, the above code would execute both the
'and' part and the 'or' part, in the order they appear, but
either part can have a 'break' statement to terminate further
processing. The scope of any variables declared by the 'for'
initialization expression extends through the 'and' and 'or'
clauses.

This syntax avoids any new keywords and is backwards-compatible.
It applies equally to while loops (the 'or' statement is never
executed for a do-while loop, naturally). And it has the same
infelicitous bind-to-nearest behavior that 'else' does :-) If
you want, you could require compound-statements for the 'and'
and 'or' parts, as 'try' and 'catch' do.

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





Author: Jared Grubb <jared.grubb@gmail.com>
Date: Fri, 7 Aug 2009 11:56:19 CST
Raw View
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";
}

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
}

Being able to insert some code that runs when the loop condition is
false can be useful, even if it is somewhat rare. I've seen examples
in live code where developers solve this by:
1) re-testing the loop condition,
2) using an extra flag-variable declared outside of the for loop that
can be tested after the for loop finished (e.g., put "bool
success=false" outside the loop in the second example),
3) by encapsulating the for-loop in a separate function (the "break"
becomes "return" and the extra code follows the for loop).

The first two solutions result in code that is not as readable and
even awkward (once you know how "for-else" works -- it's a little
strange at first glance). The third solution is probably the best way
to do it, but sometimes encapsulating the for-loop out is not easy or
nice.

I tried to find if this has ever been discussed, and I haven't been
able to find any previous discussion on this construct. So, I was
curious if anyone else had an opinion on whether this kind of
construct would be useful.

Jared

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