Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Breaking out of nested loops

543 views
Skip to first unread message

JiiPee

unread,
Feb 28, 2018, 7:55:43 PM2/28/18
to
|for(inti =0;i <m;i++){for(intj =0;j <n;j++){if(some condition){// Do
something and break...gotoafterLoop;// Breaks out of both
loops}}}afterLoop: I googled and this seems to be manys preferably way.
I have this often. How would you break nested loops? Somebody said
Substroup said this is ok. |

JiiPee

unread,
Feb 28, 2018, 7:58:15 PM2/28/18
to
Sorry first message was a mess, so reposting it:

for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
         if (some condition) {
             // Do something and break...
             goto afterLoop; // Breaks out of both loops

Alf P. Steinbach

unread,
Feb 28, 2018, 8:08:47 PM2/28/18
to
`return` is nice.

`throw` can also do the job but would be both counter-idiomatic
(contra-idiomatic? what?) and inefficient.

void foo()
{
for( int i = 0; i < m; ++i ) for( int j = 0; j < n; ++j )
{
if( some_condition )
{
return;
}
}
}

void bar()
{
preamble();
foo();
more_stuff();
}

Cheers!,

- Alf

JiiPee

unread,
Feb 28, 2018, 8:12:48 PM2/28/18
to
On 01/03/2018 01:08, Alf P. Steinbach wrote:
>
> `return` is nice.
>
> `throw` can also do the job but would be both counter-idiomatic
> (contra-idiomatic? what?) and inefficient.
>
>      void foo()
>      {
>          for( int i = 0; i < m; ++i ) for( int j = 0; j < n; ++j )
>          {
>              if( some_condition )
>              {
>                  return;
>              }
>          }
>      }
>
>      void bar()
>      {
>          preamble();
>          foo();
>          more_stuff();
>      }
>
>

Ok, so you move the for loop into its own function. And I see some use
lambdas. But then if you are using a lot of variables in that loop you
would need to pass them. Lets say it uses 10 variables... wouldnt it be
a bit difficult to pass all 10 parameters into this function? Also the
for loop now is not in the place where the action is... isnt it better
the loop is there where it should be? How about lambda?


Ian Collins

unread,
Feb 28, 2018, 8:21:47 PM2/28/18
to
On 03/01/2018 02:12 PM, JiiPee wrote:
> On 01/03/2018 01:08, Alf P. Steinbach wrote:
>>
>> `return` is nice.
>>
>> `throw` can also do the job but would be both counter-idiomatic
>> (contra-idiomatic? what?) and inefficient.
>>
>>      void foo()
>>      {
>>          for( int i = 0; i < m; ++i ) for( int j = 0; j < n; ++j )
>>          {
>>              if( some_condition )
>>              {
>>                  return;
>>              }
>>          }
>>      }
>>
>>      void bar()
>>      {
>>          preamble();
>>          foo();
>>          more_stuff();
>>      }
>>
>>

Posting a mess again....

> Ok, so you move the for loop into its own function. And I see some use
> lambdas.

Where?

> But then if you are using a lot of variables in that loop you
> would need to pass them. Lets say it uses 10 variables... wouldnt it be
> a bit difficult to pass all 10 parameters into this function?

Encapsulate the functions an variables in an object.

> Also the
> for loop now is not in the place where the action is... isnt it better
> the loop is there where it should be?

Where's that?

> How about lambda?

?

--
Ian.

JiiPee

unread,
Feb 28, 2018, 8:52:58 PM2/28/18
to
On 01/03/2018 01:21, Ian Collins wrote:
>> Also the
>> for loop now is not in the place where the action is... isnt it better
>> the loop is there where it should be?
>
> Where's that?


like:

// some code

// for-loops

// more code

now its a bit beneficial if the for loop action can be seen in the
section "// for-loops". If that is replaced by a function then you
cannot see what the for loop is doing unless you scroll and find that
for loop function.

Christiano

unread,
Feb 28, 2018, 9:00:25 PM2/28/18
to
I thought of something like:

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (some condition) {
// Do something and break...

i=m;
break;
}
}
}

But that does not seem like an elegant solution. Alf's solution
unfortunately puts it in another function.

JiiPee

unread,
Feb 28, 2018, 9:11:04 PM2/28/18
to
ok but what if you have 4 loops nested? Then would become a bit
difficult to set those indexes.

Christiano

unread,
Feb 28, 2018, 9:21:52 PM2/28/18
to
Yes.. you would have to assign (n-1) times (i, j, k, ...) before the
break statement, where n is the number of loops. And the solution with
goto seems very simple.

Bo Persson

unread,
Feb 28, 2018, 9:36:17 PM2/28/18
to
Come on now!

If you have 4 nested loops using 10 different variables, how are we
going to know their values after the goto?

Using a goto will be the smaller problem and refactoring this into
several functions seems like an even better solution than for a smaller
loop.



Bo Persson

Ian Collins

unread,
Feb 28, 2018, 9:37:07 PM2/28/18
to
If you give the function a sensible name, it won't matter.

--
Ian.


woodb...@gmail.com

unread,
Feb 28, 2018, 10:23:04 PM2/28/18
to
On Wednesday, February 28, 2018 at 7:08:47 PM UTC-6, Alf P. Steinbach wrote:
> On 01.03.2018 01:57, JiiPee wrote:
> > Sorry first message was a mess, so reposting it:
> >
> > for (int i = 0; i < m; i++) {
> >     for (int j = 0; j < n; j++) {
> >          if (some condition) {
> >              // Do something and break...
> >              goto afterLoop; // Breaks out of both loops
> >          }
> >     }
> > }
> > afterLoop:
> >
> > I googled and this seems to be manys preferably way. I have this often.
> > How would you break nested loops? Somebody said Substroup said this is ok.
>
> `return` is nice.
>
> `throw` can also do the job but would be both counter-idiomatic
> (contra-idiomatic? what?) and inefficient.
>

Merriam-Webster has this:

Synonyms of idiomatic

individual, individualized, particular, patented, peculiar, personal, personalized, private, privy, separate, singular, subjective, unique

-------------------------------------------------

It would be dubious to use a throw in that case.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Jorgen Grahn

unread,
Mar 1, 2018, 1:44:35 AM3/1/18
to
On Thu, 2018-03-01, JiiPee wrote:
...
> ok but what if you have 4 loops nested? Then would become a bit
> difficult to set those indexes.

Four nested loops, a need to break from the inner one, 10 variables
involved ... I think you're making the mistake of inventing the worst
possible case, and then looking for a general solution for everything.

I'd look for a solution in a concrete real-life case instead.

And I cannot even remember last time I had to solve this. My gut
feeling is that splitting out a helper function was the right,
readable solution that time.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Öö Tiib

unread,
Mar 1, 2018, 1:49:54 AM3/1/18
to
Note that algorithm with 4 loops nested has O(m*n*o*p) time
complexity. If these loop over anything of significance then such
brute force loop may take literally ages and so setting indexes
is likely smallest of difficulties with it. Actual difficulty is
usually that one should start to think at that spot.

Chris Vine

unread,
Mar 1, 2018, 5:39:20 AM3/1/18
to
In case Alf gets confused by your posting, you need to get a better
dictionary since that is not the meaning of the word in English. In
this context it means something characteristic of or appropriate to a
particular field of endeavour. "Idiomatic English" is english as
spoken colloquially by a native speaker.

In this case "counter-idiomatic" means an approach to the use of
exceptions which is not commonly adopted by those experienced in writing
C++ programs. Which was his intended meaning.

It would not be "dubious" at all to throw exceptions in cases where it
is idiomatic to do so. You might want to think twice where it is
counter-idiomatic however. (I put "dubious" in quotes because that
is a counter-idiomatic use of the word in English.)

guy.tr...@gmail.com

unread,
Mar 1, 2018, 6:09:44 AM3/1/18
to
On Thursday, March 1, 2018 at 1:21:47 AM UTC, Ian Collins wrote:
> On 03/01/2018 02:12 PM, JiiPee wrote:
[snip]
> > Ok, so you move the for loop into its own function. And I see some use
> > lambdas.
>
> Where?

something like:

[&](){
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (condition) return;
}
}
}();

Alf P. Steinbach

unread,
Mar 1, 2018, 8:55:40 AM3/1/18
to
On 01.03.2018 01:57, JiiPee wrote:
I forgot to mention, you can also use a single 2D index and ordinary
`break` from the then single `for` loop, like this:

#include <iostream>
#include <iomanip>
using namespace std;

auto main()
-> int
{
const int w = 5;
const int h = 7;
for( my::Indices indexing{{ w, h }}; not indexing.at_end();
++indexing )
{
if( inner( indexing ) == 3 and outer( indexing ) == 5 )
{
break;
}

const bool first_item = (inner( indexing ) == 0);
const bool new_row = (first_item and outer( indexing )
> 0);

cout << (new_row? "\n" : first_item? "" : ", ");
cout << setw( 2 ) << inner( indexing ) + 5*outer( indexing );
}
cout << endl;
}

Support machinery that can easily be made reusable (amortized O(1)
programmer's time):

#include <array>

namespace my{
using std::array;

struct Indices
{
static constexpr int n = 2;

array<int, n> const limits;
array<int, n> values;

void operator++()
{
for( int i = 0; i < n; ++i )
{
int& index = values[i];
++index;
if( index != limits[i] )
{
break;
}
index = 0;
}
}

auto at_end() const
-> bool
{
for( int i = 0; i < n - 1; ++i )
{
if( values[i] != 0 )
{
return false;
}
}
return values.back() == limits.back();
}
};

inline auto inner( Indices& indexing )
-> int&
{ return indexing.values[0]; }

inline auto outer( Indices& indexing )
-> int&
{ return indexing.values[1]; }

} // namespace my

Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Mar 1, 2018, 8:58:55 AM3/1/18
to
Oh so nice there's a bug -- to find. :-)

Cheers!

- Alf

JiiPee

unread,
Mar 1, 2018, 12:40:17 PM3/1/18
to
yes thats what I meant. benefit is that you can see the code in the place

JiiPee

unread,
Mar 1, 2018, 12:45:37 PM3/1/18
to
On 01/03/2018 02:21, Christiano wrote:
> And the solution with goto seems very simple.


Just first time testing goto in my code to see how it works.

But sure sometimes the solution is to make better code structure.. but
its a handy solution for quick fix if perfect code not needed.

JiiPee

unread,
Mar 1, 2018, 12:47:12 PM3/1/18
to
On 01/03/2018 02:35, Bo Persson wrote:
> If you have 4 nested loops using 10 different variables, how are we
> going to know their values after the goto?

no but how about a very simple 4 nested loop (like doing only one
assigment and having 0-1 variables). Then goto would work pretty well?

JiiPee

unread,
Mar 1, 2018, 12:58:50 PM3/1/18
to
Ok, so how about lets say we have to do that 4 nested loop like this:

for (int i= 0; i <= 5; +i)
for (int i2= 0; i2 <= 5; +i2)
for (int i3= 0; i3 <= 5; +i3)
for (int i4= 0; i4 <= 5; +i4)
  if(checkCondition(i, i2, i3, i4))
    goto end_loop;
endloop:

so here is no variables and one simple function call. So how would you
end that otherwise than using a goto?


James R. Kuyper

unread,
Mar 1, 2018, 1:26:37 PM3/1/18
to
On 03/01/2018 12:58 PM, JiiPee wrote:
> Ok, so how about lets say we have to do that 4 nested loop like this:
>
> for (int i= 0; i <= 5; +i)

That should be ++i, not +i. "+i" is well-formed code that has no useful
effect in this context.
If there were an operator overload for unary + that applied to i, that
would be a different matter - but you can't overload operators for int.

> for (int i2= 0; i2 <= 5; +i2)
> for (int i3= 0; i3 <= 5; +i3)
> for (int i4= 0; i4 <= 5; +i4)
>   if(checkCondition(i, i2, i3, i4))
>     goto end_loop;
> endloop:

You wrote end_loop and endloop right next to each other, and managed to
spell them differently? :-)

If checkCondition() returns a value that depends only upon the values of
it's arguments, and has no side-effects, then all of the above code
could be optimized away.
If that's not the case, I would need to know what checkCondition() does
that means it can't be optimized away, in order to answer the following
question:

> so here is no variables and one simple function call. So how would you
> end that otherwise than using a goto?

However, while I am among the most fanatical "goto" opponents (partially
due to a traumatic experience with thousands of lines of spaghetti
FORTRAN code on my first paid programming job), I'm not sufficiently
fanatical to deny that code similar to this could be a legitimate reason
for using one.

Real Troll

unread,
Mar 1, 2018, 1:40:54 PM3/1/18
to
What does CheckCondition do? Generally I would break from the loop if
certain conditions are satisfied like in this example:

for (int i = 1; i < 10; i++)
{
cout << i << '\n';
if (i == 4)
break;
}

Öö Tiib

unread,
Mar 1, 2018, 2:50:36 PM3/1/18
to
There are nothing wrong with using goto to exit nested loops. It is valid
sentence in C++ language. That sentence is very rarely used not
because it is bad but because there is often something else wrong
with code that uses it. Too lot of nested brute force loops may be
such "wrong".

I don't remember a case in last 25 years when usage of goto
was raised as issue itself in review. I remember couple cases where
while loop together with continue was used as goto and received
"better use goto" in review.

It is worth to note that the compilers tend to optimize code that uses
goto's more carefully. It may be quality of implementation issue and
it usually does not matter.

Öö Tiib

unread,
Mar 1, 2018, 3:21:28 PM3/1/18
to
There is nothing wrong with goto there. It has been already replied
that it can be replaced with making the loop separate function
and using return instead of goto in it. Also it has been already
replied that it involving loop can be indicated with function name
(like "deep_loop()").

guinne...@gmail.com

unread,
Mar 1, 2018, 5:33:08 PM3/1/18
to
That code is the equivalent of

If (checkCondition(0, 0, 0, 0))
{
goto end_loop; // wherever that is - you didn’t show it
}
else
{
for (;;)
{
// loop perpetually, doing nothing useful
}
}


JiiPee

unread,
Mar 1, 2018, 10:54:26 PM3/1/18
to
Are you talking about the syntactical errors: +i => ++i? yes was mean to
be ++i

JiiPee

unread,
Mar 1, 2018, 11:03:17 PM3/1/18
to
On 01/03/2018 20:20, Öö Tiib wrote:
> On Thursday, 1 March 2018 19:58:50 UTC+2, JiiPee wrote:
>> Ok, so how about lets say we have to do that 4 nested loop like this:
>>
>> for (int i= 0; i <= 5; +i)
>> for (int i2= 0; i2 <= 5; +i2)
>> for (int i3= 0; i3 <= 5; +i3)
>> for (int i4= 0; i4 <= 5; +i4)
>>   if(checkCondition(i, i2, i3, i4))
>>     goto end_loop;
>> endloop:
>>
>> so here is no variables and one simple function call. So how would you
>> end that otherwise than using a goto?
> There is nothing wrong with goto there. It has been already replied

Yes just wanted to hear experienced peoples opinions. First time I am
also using it. I just used it in my code and checking hoe it goes.

I only use goto if I dont have anything better at that moment. Like a
long function and for some reason (no time, lazyness or just liking that
long function! etc) and need to do a long jump there. I couple of times
used it and felt actually fine with it there.

Some programmers say they want long functions (C programmers mostly) in
order to see clearly what is happening. Others use only small functions
for everything. I kinda go in the middle: sometimes long functions but
mostly short ones. Sometimes I feel that in a long function I can see
all clearly and if am sure that code does not need to be changed then I
felt like making it long.

> that it can be replaced with making the loop separate function
> and using return instead of goto in it.

I kinda feel like I want to see that for loop "in place" (especially if
its short) so I dont need to scroll to see it. But maybe a matter of
getting used to doing different things. thats why I like lambdas: can
see in-place what is happening.

Ian Collins

unread,
Mar 1, 2018, 11:19:51 PM3/1/18
to
On 03/02/2018 05:03 PM, JiiPee wrote:
> On 01/03/2018 20:20, Öö Tiib wrote:
>> On Thursday, 1 March 2018 19:58:50 UTC+2, JiiPee wrote:
>>> Ok, so how about lets say we have to do that 4 nested loop like this:
>>>
>>> for (int i= 0; i <= 5; +i)
>>> for (int i2= 0; i2 <= 5; +i2)
>>> for (int i3= 0; i3 <= 5; +i3)
>>> for (int i4= 0; i4 <= 5; +i4)
>>>   if(checkCondition(i, i2, i3, i4))
>>>     goto end_loop;
>>> endloop:
>>>
>>> so here is no variables and one simple function call. So how would you
>>> end that otherwise than using a goto?
>> There is nothing wrong with goto there. It has been already replied
>
> Yes just wanted to hear experienced peoples opinions. First time I am
> also using it. I just used it in my code and checking hoe it goes.
>
> I only use goto if I dont have anything better at that moment. Like a
> long function and for some reason (no time, lazyness or just liking that
> long function! etc) and need to do a long jump there. I couple of times
> used it and felt actually fine with it there.

Short functions are easier to read, easier to test and easier to avoid
the delusion that you need a goto...

> Some programmers say they want long functions (C programmers mostly) in
> order to see clearly what is happening. Others use only small functions
> for everything. I kinda go in the middle: sometimes long functions but
> mostly short ones. Sometimes I feel that in a long function I can see
> all clearly and if am sure that code does not need to be changed then I
> felt like making it long.

You end up loosing the wood for the trees. It's much clearer for most
readers to see the logic of a function if the (to them) irrelevant
detail is elsewhere. If they want to see the details, they can find it,
if they don't it isn't in their face. They have a choice!

>> that it can be replaced with making the loop separate function
>> and using return instead of goto in it.
>
> I kinda feel like I want to see that for loop "in place" (especially if
> its short) so I dont need to scroll to see it. But maybe a matter of
> getting used to doing different things. thats why I like lambdas: can
> see in-place what is happening.

As I sad before, give the function with the details a meaningful name
and this won't be a problem.

If you used a goto in my team, you would probably end up wearing a road
code on your head for the week!

--
Ian.


Ralf Goertz

unread,
Mar 2, 2018, 4:59:02 AM3/2/18
to
Am Thu, 1 Mar 2018 17:58:37 +0000
schrieb JiiPee <n...@notvalid.com>:
I sometimes have a somewhat different problem whose solution might be
applicable here as well. Suppose you don't know in advance how many
nested loops there will be and their ranges aren't necessarly the same
like they are in your example. Then you can still use just one loop and
therefore just one break:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

typedef vector<unsigned long> vec_type;

int main(int argc, char *argv[]) {
if (argc==1) {
cerr<<"usage "<<argv[0]<<" n_1 n_2 … n_n\n\nwhere [0…n_i) is the range of the i'th loop\n";
return -1;
}
vec_type n(argc-1),m(n);
for (int i=1;i<argc;++i) {
m[i-1]=stoul(argv[i]);
}
if (m==n) return 0; //nothing to do
bool stop;
do {
//do something
copy(n.begin(),n.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//do I need to break?
if (count_if(n.begin(),n.end(),[](vec_type::value_type i) {return i==1;})==2)
break;
//next
stop=true;
for (int i=0;i<n.size();++i) {
if (++n[i]>=m[i]) {
n[i]=0;
} else {
stop=false;
break;
}
}
} while (!stop);
}



JiiPee

unread,
Mar 2, 2018, 7:17:24 AM3/2/18
to
On 02/03/2018 04:19, Ian Collins wrote:
> If you used a goto in my team, you would probably end up wearing a
> road code on your head for the week!

even using goto in the above example?

Jorgen Grahn

unread,
Mar 2, 2018, 4:32:19 PM3/2/18
to
On Fri, 2018-03-02, JiiPee wrote:
...
> Some programmers say they want long functions (C programmers mostly) in
> order to see clearly what is happening. Others use only small functions
> for everything. I kinda go in the middle: sometimes long functions but
> mostly short ones. Sometimes I feel that in a long function I can see
> all clearly and if am sure that code does not need to be changed then I
> felt like making it long.

It depends on how it's done and how you look at it. Let's say you
have a 100-line function. If you split it into four 25-line
functions, the code is going to be worse. If you can extract a
function with a clear and memorable meaning, I think most people won't
mind that, even if the function is only used once.

Richard

unread,
Mar 2, 2018, 5:22:57 PM3/2/18
to
[Please do not mail me a copy of your followup]

Jorgen Grahn <grahn...@snipabacken.se> spake the secret code
<slrnp9jgmc.e...@frailea.sa.invalid> thusly:

>On Fri, 2018-03-02, JiiPee wrote:
>> Some programmers say they want long functions (C programmers mostly) in
>> order to see clearly what is happening. Others use only small functions
>> for everything. I kinda go in the middle: sometimes long functions but
>> mostly short ones. Sometimes I feel that in a long function I can see
>> all clearly and if am sure that code does not need to be changed then I
>> felt like making it long.

C programmers write long functions because they have little to no
facilities for abstraction.

>It depends on how it's done and how you look at it. Let's say you
>have a 100-line function. If you split it into four 25-line
>functions, the code is going to be worse.

Meh. As stated in terms of statement counts, it's hard to say either
way. The reason "comments" are listed as a code smell by Fowler[1]
is that long functions are often naturally broken up into smaller
chunks separated by blank lines and a little comment:

void f()
{
// step 1: ...
...

// step 2: ...
...

// step 3: ...
...
}

This is already written as a sequence of higher level operations, they
just aren't using the facilities of the language to express that
directly in code. When f() has lots of intermediate state held in
many variables, then extracting the pieces in C is painful because it
imposes large argument lists on the extracted pieces.

In C++, if f() is a method then the intermediate state is more likely
to be held in instance variables for the enclosing class and
extracting more methods results in reasonable argument lists. In the
extreme case, you might do Replace Method with Method Object and push
all the local state into instance member state on the new method
object.

In my experience in refactoring long methods, pulling out the larger
chunks is usually quite easy and results in a method that clearly
states the larger steps taken to achieve the final result. The
original long function becomes a "sergeant" function: it doesn't do
the work directly, it delegates the work out to private methods that
do the work.

>If you can extract a
>function with a clear and memorable meaning, I think most people won't
>mind that, even if the function is only used once.

Stroustrup talks about how most functions should be about 5 lines
long or less. Imagine how you get to that from a 100 line function.
Practicing this transformation is not only instructive in practicing
refactoring, it is instructive in the design mindset. To get to 5
line functions you need to have lots of fine-grained abstractions that
you can easily reuse and you find yourself reaching for the standard
library algorithms more often. (Replace 5 lines of custom loop with 1
invocation of a standard library algorithm.) I think Ranges will make
this style of use of the standard library algorithms even more readable
as 99% of the time you operate on the entire container and not a
subrange.

It's the zero-overhead abstraction facilities of C++ that make this
possible. In C, we have no facilities for creating a value type that
encapsulates things like "2D point", "2D vector", etc., so we are
forced to write low-level details all the time. I hear C programmers
saying that this is a feature not a bug because "they know exactly
what is happening all the time", but IMO this is simply a
rationalization for not thinking at a level beyond low-level details.
It is possible to use abstractions in C, but the level of manual
mechanical fiddling is burdensome, repetitive and boring. C++
provides these mechanisms already, so just use it.

[1] Fowler, Martin: "Refactoring: Improving the Design of Existing Code"
<http://amzn.to/2oDj4aC>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

JiiPee

unread,
Mar 3, 2018, 8:28:12 AM3/3/18
to
Yes this is how I also have been thinking. It depends what the code is
doing. Preferable I would split it to 4 sections, but if its messy to do
that and it takes a lot of work etc.. then I have been leaving it long.
And yes if its logical to split it then preferably I split it.

>

JiiPee

unread,
Mar 3, 2018, 8:33:25 AM3/3/18
to
Surely I dont disagree that 6 lines functions good. I guess am talking
about rare instances where longer function seems like an option.
But reducing repetion inside a function I found lambdas do a good job as
you can place them also inside the function and near your code and they
are easy to make.

bartc

unread,
Mar 3, 2018, 11:04:23 AM3/3/18
to
On 01/03/2018 11:09, guy.tr...@gmail.com wrote:
How about just writing:

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (condition) break all;
}
}


Then no lambdas, extraneous functions or gotos are needed.

It also allows you to have an actual return from the original function
within the loops, which is going to be awkward from inside a lambda or
inside another function. And it can help disambiguate a loop break from
a switch break, when the if is inside a switch statement (I assume C++
still has this quirk).

It's a no-brainer.

Of course, such a feature would need to be added, but I suspect it's too
simple, too useful and too sensible to make the short list.

--
bartc

bartc

unread,
Mar 3, 2018, 4:03:45 PM3/3/18
to
On 02/03/2018 22:22, Richard wrote:

> Stroustrup talks about how most functions should be about 5 lines
> long or less.

I can't believe that was a serious opinion. Presumably that 5 lines is
after you've taken account of the function declaration, { and } which
might go on their own lines, comments and blank lines, and perhaps a
line to introduce some local declarations. If the function returns a
result, then at least one line will have a 'return' statement.

That's already have 6 or 7 lines and we haven't written any actual code yet!

I've just done a search for 'stroustrup c++ examples', and the first
link had a couple of examples with nearer 20 lines. They mainly
consisted of a switch statement with two cases.

Presumably, switch statements with more than a handful of cases wouldn't
be allowed, even if there was only one line of code (a function call)
for each case label, written like this to save vertical space:

case x: fn(a,b); break;

It sounds a ridiculous claim. Even more so when you consider that C and
C++ make a big deal about block scopes to localise declarations within a
function. With only 5 lines to play with, you're not going to be able to
declare many such scopes!


> Imagine how you get to that from a 100 line function.

If you can see the whole function in an editor window, then there is no
need to make it any smaller unless that are other considerations for
doing so.

> Practicing this transformation is not only instructive in practicing
> refactoring, it is instructive in the design mindset. To get to 5
> line functions

I can't imagine anything more exasperating than thousands of tiny
functions so that have you have to keep chasing calls all over the
source to help build a picture of what the code is supposed to be doing.

Except when there are hundreds of tiny files as well.

--
bartc

Ian Collins

unread,
Mar 3, 2018, 9:54:31 PM3/3/18
to
On 03/04/2018 10:03 AM, bartc wrote:
> On 02/03/2018 22:22, Richard wrote:
>
> If you can see the whole function in an editor window, then there is no
> need to make it any smaller unless that are other considerations for
> doing so.

There are other considerations, a very important one being ease of
testing. The longer a function becomes:

- The harder it is to test
- You need many more test cases, the growth is a non-linear
function of the line length.
- You end up with testable functionality buried in the function.
- You end up with reusable functionality buried in the function.

These effects and others are why you seldom see long functions in test
driven code.

>> Practicing this transformation is not only instructive in practicing
>> refactoring, it is instructive in the design mindset. To get to 5
>> line functions
>
> I can't imagine anything more exasperating than thousands of tiny
> functions so that have you have to keep chasing calls all over the
> source to help build a picture of what the code is supposed to be doing.

Very few (unless you are writing Java...) call trees have "thousands of
tiny functions". Like Richard, I much prefer seeing code like

void f()
{
getSomething();

processSomething()

sendSomething();
}

or

void f( Value n )
{
switch( n )
{
case A:
processA();
break;

case B:
processB();
break;

case C:
processC();
break;
}
}

Than seeing all of the guts in one place. If I want to get an overview
I can quickly do so and if I want to drill down, I can. The important
thing is I have a choice.

This style of code is much easier to write in C++ than it is in C, which
might be why someone coming from a C background isn't used to seeing it.

--
Ian

Ian Collins

unread,
Mar 3, 2018, 9:54:51 PM3/3/18
to
Yes.

--
Ian.

Ian Collins

unread,
Mar 3, 2018, 9:56:59 PM3/3/18
to
Localised error handling is an excellent use case for lambdas, just take
care not to overuse them!

--
Ian

Richard

unread,
Mar 4, 2018, 12:10:14 AM3/4/18
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<fg15ep...@mid.individual.net> thusly:

>This style of code is much easier to write in C++ than it is in C, which
>might be why someone coming from a C background isn't used to seeing it.

Bingo. C++'s ability to define abstractions at zero runtime cost are
why you can do this reasonably in C++, but not in C.

Gareth Owen

unread,
Mar 4, 2018, 4:36:55 AM3/4/18
to
Ian Collins <ian-...@hotmail.com> writes:

> On 03/04/2018 10:03 AM, bartc wrote:
>> On 02/03/2018 22:22, Richard wrote:
>>
>> If you can see the whole function in an editor window, then there is no
>> need to make it any smaller unless that are other considerations for
>> doing so.
>
> There are other considerations, a very important one being ease of
> testing. The longer a function becomes:
>
> - The harder it is to test

Hmmm. I'm not sure I agree with this. When testing a function, the
only thing I need to know are the pre-conditions and post-conditions.
Any properties of the implementation (function length, multiple
exit-points, modularity, use of sub-routines, dependence on external
libraries)

Indeed, if we write our tests first, how can the test suite possibly
depend on the function length?

Rather, everything you say applies to functions that only have a small
number of pre/post-conditions (i.e. *simple* functions, rather than
short [although we expect these to correlate pretty strongly, especially
if the language is sufficiently expressive (i.e. not C)]).

Of course, modularity makes it easier to test sub-components during
development...

JiiPee

unread,
Mar 4, 2018, 10:31:34 AM3/4/18
to
I use lambdas also inside a function if there is repetition (even maybe
2-3 repetitions). I dont like to repeat things :)

Ian Collins

unread,
Mar 4, 2018, 11:43:09 PM3/4/18
to
On 03/04/2018 10:36 PM, Gareth Owen wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>
>> On 03/04/2018 10:03 AM, bartc wrote:
>>> On 02/03/2018 22:22, Richard wrote:
>>>
>>> If you can see the whole function in an editor window, then there is no
>>> need to make it any smaller unless that are other considerations for
>>> doing so.
>>
>> There are other considerations, a very important one being ease of
>> testing. The longer a function becomes:
>>
>> - The harder it is to test
>
> Hmmm. I'm not sure I agree with this. When testing a function, the
> only thing I need to know are the pre-conditions and post-conditions.

You also need to know the function's dependencies. Even a function with
simple preconditions and postconditions such as reading a file will have
dependencies such as what happens if open fails? What happens if read fails?

The more work a function has to do, the more numerous its dependencies
are likely to become. It will also have more code paths to test. I
guess an extreme example would be to say a single function image file
converter is easy to test give its preconditions and postconditions are
simple...

> Indeed, if we write our tests first, how can the test suite possibly
> depend on the function length?

It doesn't, you could end up with a large number of test cases for a
single function, but that isn't normally how things end up.

> Rather, everything you say applies to functions that only have a small
> number of pre/post-conditions (i.e. *simple* functions, rather than
> short [although we expect these to correlate pretty strongly, especially
> if the language is sufficiently expressive (i.e. not C)]).
>
> Of course, modularity makes it easier to test sub-components during
> development...

Which was one of my (snipped) points!

--
Ian.

Egor

unread,
Mar 5, 2018, 11:37:59 AM3/5/18
to
Ian Collins <ian-...@hotmail.com> wrote:
> If you used a goto in my team, you would probably end up wearing a road
> code on your head for the week!

Blindly avoiding goto statement at all cost is a great example of cargo
cult programming. It's widely known that goto is usually frowned upon,
but not many know *why* it is considered a Bad Thing(tm).

Dijkstra's "Goto Statement Considered Harmful" popuralized the notion
that goto makes code unreadable. His argument was that it is difficutlt
for humans to visualize processes involving time, so to make code more
eadable, time should be roughly mapped to the position in program text.
With goto statement, it can't be guaranteed that the program text will
be ordered this way.

In other words, you *can* write sphagetti code with goto. However, this
doesn't mean that goto always results in such code. In fact, there are
multiple patterns, including the double-break, which read like a hack
when written in the best traditions of structured programming, while
the goto version is clean and straightforward.

To conclude, when used properly, goto doesnt sacrifice readability, but
actually improves it.

Richard

unread,
Mar 5, 2018, 12:57:13 PM3/5/18
to
[Please do not mail me a copy of your followup]

Egor <eg...@ruby.local> spake the secret code
<mh70ne-...@ruby.opensrc.club> thusly:

>Dijkstra's "Goto Statement Considered Harmful" popuralized the notion
>that goto makes code unreadable. His argument was that it is difficutlt
>for humans to visualize processes involving time, so to make code more
>eadable, time should be roughly mapped to the position in program text.
>With goto statement, it can't be guaranteed that the program text will
>be ordered this way.

It should be noted that at the time Dijkstra wrote his paper (1968),
languages supporting structured programming were not common and
structured programming itself was even less common. For background,
the Wikipedia page on Goto seems to do a good job:
<https://en.wikipedia.org/wiki/Goto>

Probably the most commonly used languages at the time were FORTRAN and
COBOL. I don't have data, but my feeling was that FORTRAN was more
widely used than COBOL at the time, but that could just be my
scientific oriented tastes selecting what I know about computing
history.

In 1968, I'd say that the FORTRAN most people used was FORTRAN 66 or
an earlier variant. FORTRAN 66 does not have structured block
statements; that wouldn't show up until FORTRAN 77 in a standardized
version.
<https://en.wikipedia.org/wiki/Fortran>

>In other words, you *can* write sphagetti code with goto.

...and at the time Dijkstra wrote his paper, this was the common case.
FORTRAN 66 has GOTO, computed GOTO, assigned GOTO, single statement IF
(most often used with GOTO) and three-way (arithmetic) IF.

If you've ever seen BASIC or GOTO code from the 60s or 70s, it is
littered with GOTO statements and even having gotten used to the
programming language limitations, the control flow is difficult to
read, follow and understand.

From the current day perspective where block structures are ubiquitous
in nearly every programming language (even those lacking GOTO), it is
easy to poke sticks at Dijkstra's paper and rehabilitate GOTO. My
assertion is that anyone who'd seen the common code of the day is
happy to say goodbyte to GOTO :-).

About the only useful construct I can think of for which GOTO is
considered necessary is Duff's device. I haven't seen any studies
on a modern compiler that automatically unrolls loops to know if it is
any better than unrolling by hand for something like this.
<https://en.wikipedia.org/wiki/Duff%27s_device>
<http://wiki.c2.com/?DuffsDeviceInDuffsOwnWords> (ha ha ha ha, he was
dumping words into the command FIFO of an E&S Picture System II!)

Richard

unread,
Mar 5, 2018, 12:59:00 PM3/5/18
to
[Please do not mail me a copy of your followup]

> Hmmm. I'm not sure I agree with this. When testing a function, the
> only thing I need to know are the pre-conditions and post-conditions.

You also need to know the internal branching structure of the
implementation to ensure that those pre and post conditions remain
true no matter how the function is called.

Richard

unread,
Mar 5, 2018, 1:00:33 PM3/5/18
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<fg4066...@mid.individual.net> thusly:

>[...] I
>guess an extreme example would be to say a single function image file
>converter is easy to test give its preconditions and postconditions are
>simple...

Au contraire because the code that reads and writes image file formats
has lots of branches and data dependencies. :-)

So while it "looks simple" at the application layer, the underlying
file reader/writer code is quite complicated for anything but even the
most braindead of formats (e.g. raw RGB byte dump).

Richard

unread,
Mar 5, 2018, 1:04:42 PM3/5/18
to
[Please do not mail me a copy of your followup]

(Richard) legaliz...@mail.xmission.com spake the secret code
<p7k0dc$ob5$1...@news.xmission.com> thusly:

>About the only useful construct I can think of for which GOTO is
>considered necessary is Duff's device. I haven't seen any studies
>on a modern compiler that automatically unrolls loops to know if it is
>any better than unrolling by hand for something like this.
><https://en.wikipedia.org/wiki/Duff%27s_device>
><http://wiki.c2.com/?DuffsDeviceInDuffsOwnWords> (ha ha ha ha, he was
>dumping words into the command FIFO of an E&S Picture System II!)

...and even in Duff's device, the goto is done via switch, so you
don't even need goto for that :).

Robert Wessel

unread,
Mar 5, 2018, 2:58:54 PM3/5/18
to
One of the main issues Dijkstra was writing about was the use of gotos
with very large spans. People in those days people were writing Cobol
programs of many thousands* of lines, with gotos jumping willy-nilly
all over that mass. In most cases, with "modern" sized functions,
even grossly unstructured and goto-laden code would be much less of a
problem. The amount of control flow insanity possible in a 50 line
routine is inherently limited. That's made even better when you
restrict goto usage to one of a few idioms which are well understood,
and straight-forward.

And, as an aside, the problem is not so much the goto - it's hard to
imaging a more straight-forward control flow operation, rather the
code at the label, where you now have a much more complex case trying
to figure out how your program got to that point.


*10 and 20kloc Cobol programs were hardly uncommon.

Richard

unread,
Mar 5, 2018, 3:29:10 PM3/5/18
to
[Please do not mail me a copy of your followup]

Robert Wessel <robert...@yahoo.com> spake the secret code
<5r7r9dlhul3igrl9g...@4ax.com> thusly:

>[...] In most cases, with "modern" sized functions,
>even grossly unstructured and goto-laden code would be much less of a
>problem.

Getting back to C++, the most common use of a goto is to handle common
cleanup due to an error condition encountered in the middle of a
complex sequence of conditional operations. (Think COM HRESULTs
returned by almost every method invocation.) These are better handled
in C++ by RAII techniques and exceptions than goto.

Realistically, that's the entirety of where I've seen goto used in C++
code over the past couple of decades. Given that there are better,
less error-prone alternatives, I don't think there's much of a case
for goto given its most prominent use case in real-world code.

Ian Collins

unread,
Mar 5, 2018, 3:41:17 PM3/5/18
to
On 03/06/2018 05:23 AM, Egor wrote:
> Ian Collins <ian-...@hotmail.com> wrote:
>> If you used a goto in my team, you would probably end up wearing a road
>> code on your head for the week!
>
> Blindly avoiding goto statement at all cost is a great example of cargo
> cult programming. It's widely known that goto is usually frowned upon,
> but not many know *why* it is considered a Bad Thing(tm).

There's nothing blind about it. I someone can put up a good case for
why goto is the best option they'd be free to use it. I simply have
never seen this happen!

> Dijkstra's "Goto Statement Considered Harmful" popuralized the notion
> that goto makes code unreadable. His argument was that it is difficutlt
> for humans to visualize processes involving time, so to make code more
> eadable, time should be roughly mapped to the position in program text.
> With goto statement, it can't be guaranteed that the program text will
> be ordered this way.
>
> In other words, you *can* write sphagetti code with goto. However, this
> doesn't mean that goto always results in such code. In fact, there are
> multiple patterns, including the double-break, which read like a hack
> when written in the best traditions of structured programming, while
> the goto version is clean and straightforward.

Those arguments my apply to C code, where it's reasonably idiomatic to
use goto for error processing, but not to C++ where we have better tools.

> To conclude, when used properly, goto doesnt sacrifice readability, but
> actually improves it.

Maybe; however "property" has different meanings in different languages.

--
Ian.

Öö Tiib

unread,
Mar 5, 2018, 5:11:52 PM3/5/18
to
On Monday, 5 March 2018 22:41:17 UTC+2, Ian Collins wrote:
> On 03/06/2018 05:23 AM, Egor wrote:
> > Ian Collins <ian-...@hotmail.com> wrote:
> >> If you used a goto in my team, you would probably end up wearing a road
> >> code on your head for the week!
> >
> > Blindly avoiding goto statement at all cost is a great example of cargo
> > cult programming. It's widely known that goto is usually frowned upon,
> > but not many know *why* it is considered a Bad Thing(tm).
>
> There's nothing blind about it. I someone can put up a good case for
> why goto is the best option they'd be free to use it. I simply have
> never seen this happen!

The goto is rarely used like deep break, deep continue and for handling
of non-exceptional errors (some stuff in this universe is noisy).
When people who used it knew what they do then most common attempt to
rewrite it without goto will result with bit longer and not much more
readable code and little drop in efficiency. So why to bother?

Robert Wessel

unread,
Mar 5, 2018, 5:54:27 PM3/5/18
to
On Mon, 5 Mar 2018 20:28:56 +0000 (UTC),
legaliz...@mail.xmission.com (Richard) wrote:

>[Please do not mail me a copy of your followup]
>
>Robert Wessel <robert...@yahoo.com> spake the secret code
><5r7r9dlhul3igrl9g...@4ax.com> thusly:
>
>>[...] In most cases, with "modern" sized functions,
>>even grossly unstructured and goto-laden code would be much less of a
>>problem.
>
>Getting back to C++, the most common use of a goto is to handle common
>cleanup due to an error condition encountered in the middle of a
>complex sequence of conditional operations. (Think COM HRESULTs
>returned by almost every method invocation.) These are better handled
>in C++ by RAII techniques and exceptions than goto.


That and breaking out of nested loops.


>Realistically, that's the entirety of where I've seen goto used in C++
>code over the past couple of decades. Given that there are better,
>less error-prone alternatives, I don't think there's much of a case
>for goto given its most prominent use case in real-world code.


I'm certainly not arguing that goto should see frequent use, or should
be a first choice in the vast majority of cases. Rather that if a
goto improves clarity significantly, then it's not unreasonable to use
one.

I was mostly trying to provide some historical context for "Goto
Statement Considered Harmful".

Daniel

unread,
Mar 5, 2018, 6:07:51 PM3/5/18
to
On Monday, March 5, 2018 at 3:29:10 PM UTC-5, Richard wrote:

> I don't think there's much of a case for goto

I've occasionally used goto in implementing state machines, which can be more
readable in this context than switch.

Daniel

Richard

unread,
Mar 5, 2018, 7:00:38 PM3/5/18
to
[Please do not mail me a copy of your followup]

Robert Wessel <robert...@yahoo.com> spake the secret code
<oair9dhvie6ip6l3a...@4ax.com> thusly:

>On Mon, 5 Mar 2018 20:28:56 +0000 (UTC),
>legaliz...@mail.xmission.com (Richard) wrote:
>
>>[Please do not mail me a copy of your followup]
>>
>>Robert Wessel <robert...@yahoo.com> spake the secret code
>><5r7r9dlhul3igrl9g...@4ax.com> thusly:
>>
>>>[...] In most cases, with "modern" sized functions,
>>>even grossly unstructured and goto-laden code would be much less of a
>>>problem.
>>
>>Getting back to C++, the most common use of a goto is to handle common
>>cleanup due to an error condition encountered in the middle of a
>>complex sequence of conditional operations. (Think COM HRESULTs
>>returned by almost every method invocation.) These are better handled
>>in C++ by RAII techniques and exceptions than goto.
>
>That and breaking out of nested loops.

It will be interesting to see how ranges and views change that use
case.

Kan

unread,
Mar 6, 2018, 7:00:01 AM3/6/18
to
Il 01/03/2018 01:57, JiiPee ha scritto:
> Sorry first message was a mess, so reposting it:
>
> for (int i = 0; i < m; i++) {
>     for (int j = 0; j < n; j++) {
>          if (some condition) {
>              // Do something and break...
>              goto afterLoop; // Breaks out of both loops
>          }
>     }
> }
> afterLoop:
>
> I googled and this seems to be manys preferably way. I have this often.
> How would you break nested loops? Somebody said Substroup said this is ok.

What about:

bool exit_loop = false;
for (int i = 0; i < m && !exit_loop; i++) {
for (int j = 0; j < n && !exit_loop; j++) {
if (some condition) {
// Do something and break...
exit_loop = false; // Breaks out of both loops
}
}
}

Kan

unread,
Mar 6, 2018, 7:01:35 AM3/6/18
to
Ops, it should be:

bool exit_loop = false;
for (int i = 0; i < m && !exit_loop; i++) {
for (int j = 0; j < n && !exit_loop; j++) {
if (some condition) {
// Do something and break...
exit_loop = true; // Breaks out of both loops
}
}
}

asetof...@gmail.com

unread,
Mar 6, 2018, 7:51:02 AM3/6/18
to
I always use goto in all possible way and I have to know what is wrong for that... Even in Apl find a way for use good goto (as ->Labelxi(condition)) or goto as "if"
[as if(condition) ...]
->Labelxi~condition <> ...
Label:

Jorgen Grahn

unread,
Mar 6, 2018, 7:55:33 AM3/6/18
to
On Tue, 2018-03-06, Kan wrote:
> Il 06/03/2018 12:59, Kan ha scritto:
>> Il 01/03/2018 01:57, JiiPee ha scritto:
>>> Sorry first message was a mess, so reposting it:
>>>
>>> for (int i = 0; i < m; i++) {
>>>      for (int j = 0; j < n; j++) {
>>>           if (some condition) {
>>>               // Do something and break...
>>>               goto afterLoop; // Breaks out of both loops
>>>           }
>>>      }
>>> }
>>> afterLoop:
>>>
>>> I googled and this seems to be manys preferably way. I have this
>>> often. How would you break nested loops? Somebody said Substroup said
>>> this is ok.
>>
>> What about:
>>
...
> Ops, it should be:
>
> bool exit_loop = false;
> for (int i = 0; i < m && !exit_loop; i++) {
> for (int j = 0; j < n && !exit_loop; j++) {
> if (some condition) {
> // Do something and break...
> exit_loop = true; // Breaks out of both loops
> }
> }
> }

That is probably where this thread started: people feel it's so ugly
that they'd rather use goto. In my experience, there's always a
third, better option (like a return).

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Stuart Redmann

unread,
Mar 7, 2018, 3:40:40 AM3/7/18
to
Richard <legaliz...@mail.xmission.com> wrote:
[snip]
> The
> original long function becomes a "sergeant" function: it doesn't do
> the work directly, it delegates the work out to private methods that
> do the work.

Pun intended? I had to laugh heartily, it just made my day :-)

Regards,
Stuart


Stuart Redmann

unread,
Mar 7, 2018, 8:51:41 AM3/7/18
to
Öö Tiib <oot...@hot.ee> wrote:
[snip]
> I don't remember a case in last 25 years when usage of goto
> was raised as issue itself in review. I remember couple cases where
> while loop together with continue was used as goto and received
> "better use goto" in review.
>

I generally advise the opposite: if there is no better way of getting rid
of a GOTO then replace it by a while loop and use break or continue. I
consider this better readable because if you see a "break" or "continue"
you know that you have to go downwards or upwards, respectively. Whereas if
you see a GOTO you don't know whether to go upwards or downwards or even
start searching the next outer scope if there is one.

Regards,
Stuart

woodb...@gmail.com

unread,
Mar 7, 2018, 9:45:56 AM3/7/18
to
I don't use goto in either my open source or generated
code right now, but if I did it would have to refer
to something downwards rather than upwards. The use of
goto to break out of nested loops seems OK to me.


Brian
Ebenezer Enterprises - Enjoying programmings again.
http://webEbenezer.net

Öö Tiib

unread,
Mar 7, 2018, 10:58:20 AM3/7/18
to
Note that with do-while(false) both continue and break do same thing.

If the goto label was named like "gfhjlkgj" then "break" or
"continue" would indeed convey the logic better ... but
experienced programmers rarely use so bad naming.

Richard

unread,
Mar 7, 2018, 12:37:26 PM3/7/18
to
[Please do not mail me a copy of your followup]

Jorgen Grahn <grahn...@snipabacken.se> spake the secret code
<slrnp9t3tm.e...@frailea.sa.invalid> thusly:
...which ends up being more natural when you use smaller functions.

Deeply nested (here "deep" means > 2) control structures are hard to
reason about. Extracting the insides into functions with intention
revealing names generally leaves you with code that is easier to
understand and reason about and as a side benefit you get simpler
control and data flow.

Richard

unread,
Mar 7, 2018, 12:38:02 PM3/7/18
to
[Please do not mail me a copy of your followup]

Stuart Redmann <DerT...@web.de> spake the secret code
<639559663.542104545.5...@news.eternal-september.org> thusly:
I'm not the coiner of the term, but I believe the pun is intended and
that's why they chose the name "sergeant method".

JiiPee

unread,
Mar 7, 2018, 1:05:18 PM3/7/18
to
On 07/03/2018 14:45, woodb...@gmail.com wrote:
> The use of
> goto to break out of nested loops seems OK to me.

Thats what I am first time testing now in my code. I think breaking from
3 loops.

JiiPee

unread,
Mar 7, 2018, 1:06:24 PM3/7/18
to
Good point. So naming like "end_of_all_loops" would surely indicate that
we go down, right?


Gareth Owen

unread,
Mar 7, 2018, 3:02:06 PM3/7/18
to
Ian Collins <ian-...@hotmail.com> writes:

> You also need to know the function's dependencies. Even a function
> with simple preconditions and postconditions such as reading a file
> will have dependencies such as what happens if open fails? What
> happens if read fails?

Sure, but totally orthogonal to my point. (You can make a case that
failure cases are covered in post-conditions "Either the file is opened
and processed successfully and data returned in return value, or a
std::runtime_error is thrown". But as I say, not relevant.)

namespace {
inline void inner_loop(int ct,int ct2)
{
for(auto i=0;i<ct;++i) {
for(auto j=0;j<ct2;++j) {
// inner_workings();
if(condition()) return;
}
}
}

void public_func1(int ct,int ct2)
{
run_loop(ct,ct2);
}

void public_func2(int ct,int ct2)
{
void flag = false;
for(auto i=0;i < ct; ++i) {
for(auto i=0;i < ct; ++i) {
inner_loop()
if(condition()) {
flag = true;
break;
}
}
if(flag) break;
}
}

public_func1() and public_func2() are structured differently. One is
longer, the other shorter, more elegant modular. I could add plenty
more anonymous function calls to public_func1() and their inlined
equivalents to public_func2(). More than enough to get me fired.

Never the less, their test suites are identical.

> Which was one of my (snipped) points!

With which I was explicitly agreeing.

Öö Tiib

unread,
Mar 7, 2018, 5:54:22 PM3/7/18
to
Yes, if the label is where it claims then I see no problem. The
goto is very rare in actual code bases so the people who are allergic
to whatever usage of it probably became such during seventies or
eighties.

Ian Collins

unread,
Mar 7, 2018, 11:27:28 PM3/7/18
to
That's were we disagree.

If with the more modular solution, the code extracted to helper
functions can be tested independently of the parent function, so we:

a) don't have to test its behaviour when we test the parent.
b) can mock them to make testing the parent easier.

--
Ian.

asetof...@gmail.com

unread,
Mar 8, 2018, 3:33:38 AM3/8/18
to
Thank you for C++ and C

They scale well to assembly
and a convenient subset can be easy to program and debug too

But your questions on goto show some ignorance of what is readability
on what is easy and in what is difficult

Vir Campestris

unread,
Mar 8, 2018, 4:27:28 PM3/8/18
to
On 08/03/2018 04:27, Ian Collins wrote:

>
> That's were we disagree.
>
> If with the more modular solution, the code extracted to helper
> functions can be tested independently of the parent function, so we:
>
> a) don't have to test its behaviour when we test the parent.
> b) can mock them to make testing the parent easier.
>
Overuse of little worker functions can make understanding code harder.
But then, so can the 10000 line function. There's a happy medium.

I never wrote a goto in <mumble> years of coding until I met Linux. It's
a kernel standard to use goto where C++ should use throw.

Andy

Gareth Owen

unread,
Mar 9, 2018, 12:32:56 AM3/9/18
to
Ian Collins <ian-...@hotmail.com> writes:

> That's were we disagree.

Fair enough

> If with the more modular solution, the code extracted to helper
> functions can be tested independently of the parent function, so we:
>
> a) don't have to test its behaviour when we test the parent.
> b) can mock them to make testing the parent easier.

Fair enough, I can see that that has a benefit. Personally, I don't
believe in test-suites that exercise implementation details, as it
prevents effective refactoring.

Do you really write test suites / mocks that link to functions in
anonymous namespaces?

Ian Collins

unread,
Mar 9, 2018, 5:19:31 AM3/9/18
to
On 03/09/2018 06:32 PM, Gareth Owen wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>
>> That's were we disagree.
>
> Fair enough
>
>> If with the more modular solution, the code extracted to helper
>> functions can be tested independently of the parent function, so we:
>>
>> a) don't have to test its behaviour when we test the parent.
>> b) can mock them to make testing the parent easier.
>
> Fair enough, I can see that that has a benefit. Personally, I don't
> believe in test-suites that exercise implementation details, as it
> prevents effective refactoring.

It can do, but sometimes you need to go a little deeper than you would
like to get full coverage. Usually important implementation details can
be extracted and tested.

> Do you really write test suites / mocks that link to functions in
> anonymous namespaces?

Well obviously not! If something can fail in such a way as to disrupt
the behaviour of a public interface, it should also be public.

--
Ian.

Tim Rentsch

unread,
Mar 15, 2018, 12:33:42 PM3/15/18
to
You realize of course that if the code is part of an operating
system there will also need to be colonel functions.

Tim Rentsch

unread,
Mar 15, 2018, 1:37:37 PM3/15/18
to
bartc <b...@freeuk.com> writes:

> On 02/03/2018 22:22, Richard wrote:
>
>> Stroustrup talks about how most functions should be about 5 lines
>> long or less.
>
> I can't believe that was a serious opinion. Presumably that 5 lines is
> after you've taken account of the function declaration, { and } which
> might go on their own lines,

I expect it was meant as the number of lines in the function
body, ie, not including the function name, return type, parameter
declarations, or outermost definitional braces.

> comments and blank lines, and perhaps a
> line to introduce some local declarations. If the function returns a
> result, then at least one line will have a 'return' statement.

If anyone is interested, I looked at some statistics over 20 or
so small code bases (each at least 50 functions, and discarding
the two highest and two lowest). The percentage of functions of
length 5 lines or fewer ranged from about 24% to about 66%, with
about 40% as the median. The measurement includes all lines
inside function definition braces, including any blank lines or
comments.

Vir Campestris

unread,
Mar 15, 2018, 4:43:33 PM3/15/18
to
I suppose that's true in the general case :P

red floyd

unread,
Mar 15, 2018, 6:17:27 PM3/15/18
to
As long as all the code is captain the proper place.

Tim Rentsch

unread,
Mar 15, 2018, 11:01:34 PM3/15/18
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

> On Wed, 28 Feb 2018 19:22:29 -0800 (PST)
> woodb...@gmail.com wrote:
>
>> On Wednesday, February 28, 2018 at 7:08:47 PM UTC-6, Alf P. Steinbach
>> wrote:
>>
>>> On 01.03.2018 01:57, JiiPee wrote:
>>>
>>>> Sorry first message was a mess, so reposting it:
>>>>
>>>> for (int i = 0; i < m; i++) {
>>>> for (int j = 0; j < n; j++) {
>>>> if (some condition) {
>>>> // Do something and break...
>>>> goto afterLoop; // Breaks out of both loops
>>>> }
>>>> }
>>>> }
>>>> afterLoop:
>>>>
>>>> I googled and this seems to be manys preferably way. I have this
>>>> often. How would you break nested loops? Somebody said Substroup
>>>> said this is ok.
>>>
>>> `return` is nice.
>>>
>>> `throw` can also do the job but would be both counter-idiomatic
>>> (contra-idiomatic? what?) and inefficient.
>>
>> Merriam-Webster has this:
>>
>> Synonyms of idiomatic
>>
>> individual, individualized, particular, patented, peculiar, personal,
>> personalized, private, privy, separate, singular, subjective, unique
>>
>> -------------------------------------------------
>>
>> It would be dubious to use a throw in that case.
>
> In case Alf gets confused by your posting, you need to get a better
> dictionary since that is not the meaning of the word in English.

Excuse my interrupting here but I feel I should raise a complaint
about this comment. It's true this characterization is not /the/
meaning of the word idiomatic, but it is /a/ meaning of the word
idiomatic. Calling a phrase "an idiomatic construction" is very
much like saying it is individualized, peculiar, or unorthodox
(which in exteme cases could be unique). As you go on to point
out, in the context the statement was made a different meaning was
intended, but that doesn't make the dictionary wrong. It's just
that idiomatic (and also idiom) is one of those words that has
multiple, contradictory meanings. The word "sanction" is another
example - it can mean approval, but it also can mean a punishment
meant to deter. "Idiom" and "idiomatic" are like that.

> In
> this context it means something characteristic of or appropriate to a
> particular field of endeavour. "Idiomatic English" is english as
> spoken colloquially by a native speaker.
>
> In this case "counter-idiomatic" means an approach to the use of
> exceptions which is not commonly adopted by those experienced in writing
> C++ programs. Which was his intended meaning.
>
> It would not be "dubious" at all to throw exceptions in cases where it
> is idiomatic to do so. You might want to think twice where it is
> counter-idiomatic however. (I put "dubious" in quotes because that
> is a counter-idiomatic use of the word in English.)

I notice a tendency in the programming community to use the word
"idiomatic" with a connotation of being proper, accepted, or
approved in some vague sense. That's not what idiomatic means
applied to natural languge. The word "ain't" is part of idiomatic
English. It ain't good English, and it may not be commonly used
English, but it is idiomatic English. In languages like C and
C++, almost any construction that is legal is also idiomatic, in
the sense that it is being used in earnest by (some) "native
speakers" of the language. At some level using "idiomatic" in the
ways the quoted material does is a misuse of the word.

In the game of Go, there is a word "joseki" that refers to one of
a (quite large) set of well-known local opening sequences. It
translates roughly as "established pattern". A key property of
joseki is that these patterns are ones high-level players are
likely to play: sequences that are known to be bad for one side
or the other are not (or are no longer) referred to as joseki.
In labelling a particular code construction "idiomatic", what
I think is meant is more like the "established pattern" property
of joseki. I hope people will reflect on this and find a better
way to express what they mean than occurs with "idiomatic".

Tim Rentsch

unread,
Mar 16, 2018, 12:32:25 AM3/16/18
to
Robert Wessel <robert...@yahoo.com> writes:

> On Mon, 5 Mar 2018 17:57:00 +0000 (UTC),
> legaliz...@mail.xmission.com (Richard) wrote:
>
>> Egor <eg...@ruby.local> spake the secret code
>> <mh70ne-...@ruby.opensrc.club> thusly:
>>
>>> Dijkstra's "Goto Statement Considered Harmful" popuralized the
>>> notion that goto makes code unreadable. His argument was that it
>>> is difficutlt for humans to visualize processes involving time, so
>>> to make code more eadable, time should be roughly mapped to the
>>> position in program text. With goto statement, it can't be
>>> guaranteed that the program text will be ordered this way.
>>
>> [...]
>> If you've ever seen BASIC or GOTO code from the 60s or 70s, it is
>> littered with GOTO statements and even having gotten used to the
>> programming language limitations, the control flow is difficult to
>> read, follow and understand.
>>
>> From the current day perspective where block structures are
>> ubiquitous in nearly every programming language (even those lacking
>> GOTO), it is easy to poke sticks at Dijkstra's paper and
>> rehabilitate GOTO. My assertion is that anyone who'd seen the
>> common code of the day is happy to say goodbyte to GOTO :-). [...]
>
> One of the main issues Dijkstra was writing about was the use of
> gotos with very large spans. People in those days people were
> writing Cobol programs of many thousands* of lines, with gotos
> jumping willy-nilly all over that mass.

Please excuse my jumping in at the wrong point. It would have
been better to reply to an earlier posting but that isn't what
happened...

My take on what Dijkstra was trying to say is a bit different.
He did talk about keeping track of control flow in the presence
of goto (and, I might add, rather extensively). However I think
that was more of an explanation of why programs with goto are
difficult than why goto is harmful. I've seen the view expressed
(and I agree with it) that his main point is that goto is harmful
because those learning programming with goto as a key basic tool
(no pun intended) tend to write programs that are spaghettish
more than those who are taught to think in terms of the (now more
usual) structured constructs. In other words it isn't goto per
se that is bad, but the influence it has on the thinking of those
led to use it. I hardly ever use goto, but that isn't because I
think it's bad and try to avoid it. Rather, because of how I've
learned to write code, situations where a goto might be natural
(whatever that means) just tend not to come up. I don't feel
like any particular effort is needed to avoid using goto - it
simply falls out of how I think about programming.

> In most cases, with "modern" sized functions, even grossly
> unstructured and goto-laden code would be much less of a problem.
> The amount of control flow insanity possible in a 50 line routine
> is inherently limited.

Limited? Yes. Limited enough so that it's never awful? I have
to give a No on that one. :)

> That's made even better when you restrict goto usage to one of a
> few idioms which are well understood, and straight-forward.

Here you are using "idioms" more or less as a synonym for
"patterns". When used as a count noun, "idiom" has the meaning
of "peculiar construct", not "conventional pattern". It's
different when "idiom" is used as a mass noun, but that's not the
case here, as mass nouns aren't used in the plural. "That's made
even better when you restrict goto usage to one of a few common,
straightforward, and well-understood patterns" is what I think
you mean to say. (And if it isn't then I have misunderstood you
and hope you will explain.)

bitrex

unread,
Mar 16, 2018, 12:54:23 AM3/16/18
to
On 03/07/2018 12:37 PM, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Jorgen Grahn <grahn...@snipabacken.se> spake the secret code
> <slrnp9t3tm.e...@frailea.sa.invalid> thusly:
>
>> On Tue, 2018-03-06, Kan wrote:
>
>>> bool exit_loop = false;
>>> for (int i = 0; i < m && !exit_loop; i++) {
>>> for (int j = 0; j < n && !exit_loop; j++) {
>>> if (some condition) {
>>> // Do something and break...
>>> exit_loop = true; // Breaks out of both loops
>>> }
>>> }
>>> }
>>
>> That is probably where this thread started: people feel it's so ugly
>> that they'd rather use goto. In my experience, there's always a
>> third, better option (like a return).
>
> ...which ends up being more natural when you use smaller functions.
>
> Deeply nested (here "deep" means > 2) control structures are hard to
> reason about. Extracting the insides into functions with intention
> revealing names generally leaves you with code that is easier to
> understand and reason about and as a side benefit you get simpler
> control and data flow.

This "style" of code strikes me as just C in a C++ dress. Why even use
modern C++ compiler at all if this is the kind of 1976 code one wants to
write.

Alf P. Steinbach

unread,
Mar 16, 2018, 2:20:23 AM3/16/18
to
On 16.03.2018 05:32, Tim Rentsch wrote:
> Robert Wessel <robert...@yahoo.com> writes:
>
>> That's made even better when you restrict goto usage to one of a
>> few idioms which are well understood, and straight-forward.
>
> Here you are using "idioms" more or less as a synonym for
> "patterns". When used as a count noun, "idiom" has the meaning
> of "peculiar construct", not "conventional pattern". It's
> different when "idiom" is used as a mass noun, but that's not the
> case here, as mass nouns aren't used in the plural. "That's made
> even better when you restrict goto usage to one of a few common,
> straightforward, and well-understood patterns" is what I think
> you mean to say. (And if it isn't then I have misunderstood you
> and hope you will explain.)

Well that interpretation of "idiom" is not very idiomatic in programming. :)


Cheers,

- Alf

Robert Wessel

unread,
Mar 16, 2018, 4:15:36 PM3/16/18
to
One of the fundamental attributes of structured programming is the
subroutine, preferably of reasonably size.

I think we can debate as to exactly which aspects of structured
programming are the most important, but that's unlikely to achieve
much useful, but FWIW, my opinion is that cohesive and reasonably
sized subroutines are actually the fundamental building block of
clearly written programs. So it's really decomposition, and the skill
set to achieve it, that was missing from those monster unstructured
programs.

I do agree that thinking about programs in a structured way leads to
better programs (usually), but the end goal has to be something
practical, like more understandable programs. Otherwise it's just
another pointless academic exercise. In that context the lack of
structure implied by hundreds of gotos jumping willy-nilly over a
10KLOC mass of code is pretty mindboggling (if you haven't seen it,
you probably can't imaging just how bad it can be). By contrast,
while it might not be ideal, over the span of a 50 line routine, it's
a pretty minor issue. Scale is very important here.

Many people (pre-Dijkstra) writing those large programs understood at
least some of that, at least in an informal sense, and worked hard to
impose some sort of organization on their programs, although were
often hampered by poor tools (a lack of proper subroutines in Cobol*,
for example). Unfortunately programs have always had a tendency to
evolve, and that evolution is far too often done under time and const
constraints, and thus often involved violence to any "structure" in
the program. That's still true today, of course.

A similar situation are the extensive discussions of methodologies for
the development of large systems. While we can debate which
methodology we might prefer, I think we'd all agree that having *some*
plan for managing a large project is important. OTOH, if you're
writing a 1KLOC program, it just doesn't matter. Again, scale is
important.

So in the end, if everyone had been writing mostly ~50 line routines,
I don't think the lack of structure within those routines would have
attracted too much attention.



*Notwithstanding the dozens of books, papers and classes on doing
structured programming in Cobol. Until later versions of the language
this was really little better than doing structured programming in
assembler or OOP in C (both of which are obviously possible, and often
practices followed by programmers, but the tools aren't really
providing any support and that structure, or OOP, is being done
manually).



>> In most cases, with "modern" sized functions, even grossly
>> unstructured and goto-laden code would be much less of a problem.
>> The amount of control flow insanity possible in a 50 line routine
>> is inherently limited.
>
>Limited? Yes. Limited enough so that it's never awful? I have
>to give a No on that one. :)


You can, of course, write awful 50 line routines using only the three
basic SP control flows.

As I've said before, this is all about clarity, not following some
arbitrary set of rules*. I'm good with whatever makes a program
clearer. On occasion, that involves a goto. We know you *can* always
do without, but sometimes the cure is worse than the disease.


*Although in some cases arbitrary rules are a source of clarity. For
example, having a shop standard for brace placement - which placement
style you pick is pretty arbitrary**, but having everyone follow that
style, at least within a project, it quite helpful.


**So long as you pick the one obviously correct style. ;-)


>> That's made even better when you restrict goto usage to one of a
>> few idioms which are well understood, and straight-forward.
>
>Here you are using "idioms" more or less as a synonym for
>"patterns". When used as a count noun, "idiom" has the meaning
>of "peculiar construct", not "conventional pattern". It's
>different when "idiom" is used as a mass noun, but that's not the
>case here, as mass nouns aren't used in the plural. "That's made
>even better when you restrict goto usage to one of a few common,
>straightforward, and well-understood patterns" is what I think
>you mean to say. (And if it isn't then I have misunderstood you
>and hope you will explain.)


My experience is that those usages are pretty much interchangeable in
the field. Although I'd agree that in linguistic terms they're not.

Tim Rentsch

unread,
Mar 30, 2018, 2:23:39 AM3/30/18
to
I pretty much agree with all of the above. I might emphasize
that it is the drive for understandable programs that leads to
small routines, and not that a drive for small routines will
necessarily lead to understandable programs. (And which I
believe is one of the points you were making, or at least would
agree with.)

>>> In most cases, with "modern" sized functions, even grossly
>>> unstructured and goto-laden code would be much less of a problem.
>>> The amount of control flow insanity possible in a 50 line routine
>>> is inherently limited.
>>
>> Limited? Yes. Limited enough so that it's never awful? I have
>> to give a No on that one. :)
>
> You can, of course, write awful 50 line routines using only the three
> basic SP control flows.
>
> As I've said before, this is all about clarity, not following some
> arbitrary set of rules. I'm good with whatever makes a program
> clearer. On occasion, that involves a goto. We know you *can* always
> do without, but sometimes the cure is worse than the disease.

Yes. Even Dijkstra said he wasn't dogmatic about avoiding goto.
My point though is about size. Routines of 50 lines can be
manageable, and certainly they are more likely to be manageable
than routines of 100 or 200 lines. Still, 50 line routines should
be rare rather than typical. Average function length normally
should be under 20 lines, and median length closer to 10. A
length of 50 lines should normally be 95th percentile or better -
anything worse is a strong indication that some refactoring is
needed. Like what you said, I don't mean to make an arbitrary
rule, but to give a useful empirical guideline for after-the-fact
assessment.

>>> That's made even better when you restrict goto usage to one of a
>>> few idioms which are well understood, and straight-forward.
>>
>> Here you are using "idioms" more or less as a synonym for
>> "patterns". When used as a count noun, "idiom" has the meaning
>> of "peculiar construct", not "conventional pattern". It's
>> different when "idiom" is used as a mass noun, but that's not the
>> case here, as mass nouns aren't used in the plural. "That's made
>> even better when you restrict goto usage to one of a few common,
>> straightforward, and well-understood patterns" is what I think
>> you mean to say. (And if it isn't then I have misunderstood you
>> and hope you will explain.)
>
> My experience is that those usages are pretty much interchangeable in
> the field. Although I'd agree that in linguistic terms they're not.

I agree that misusage is common, but still deserves being called
out. There are two problems. The first is that different people
use the term in different ways - does it mean usual, widespread,
normal, typical, common, well-understood, generally accepted, or
some combination of those, or perhaps something else entirely?
There are arguments over whether some construction is or is not
"idiomatic". Or, another example, someone asking for "/the/
idiomatic way" (my emphasis) to write a particular program. There
is never a single good way to write a program (and yes sometimes
"idiomatic" is used as though it were synonymous with "good").
Being precise is an important habit in software development;
continuing the definitely imprecise use of "idiomatic" is
cultivating a bad habit.

The second problem is more subtle. The word "idiomatic" sounds,
by virtue of its length and narrow application, like a high-brow
word. Characterizing a pattern as "idiomatic" lends an air of
legitimacy that often is not deserved. At some level this kind of
usage is intellectually dishonest (even if not always consciously
or deliberately): it sounds objective, but as often as not boils
down to nothing more than "a pattern I think is good". That kind
of rhetorical trick is best left to the domain of politicians
(where for better or worse it appears to be inescapable).

Robert Wessel

unread,
Apr 2, 2018, 11:59:52 PM4/2/18
to
On Thu, 29 Mar 2018 23:23:26 -0700, Tim Rentsch
Yes.


>>>> In most cases, with "modern" sized functions, even grossly
>>>> unstructured and goto-laden code would be much less of a problem.
>>>> The amount of control flow insanity possible in a 50 line routine
>>>> is inherently limited.
>>>
>>> Limited? Yes. Limited enough so that it's never awful? I have
>>> to give a No on that one. :)
>>
>> You can, of course, write awful 50 line routines using only the three
>> basic SP control flows.
>>
>> As I've said before, this is all about clarity, not following some
>> arbitrary set of rules. I'm good with whatever makes a program
>> clearer. On occasion, that involves a goto. We know you *can* always
>> do without, but sometimes the cure is worse than the disease.
>
>Yes. Even Dijkstra said he wasn't dogmatic about avoiding goto.
>My point though is about size. Routines of 50 lines can be
>manageable, and certainly they are more likely to be manageable
>than routines of 100 or 200 lines. Still, 50 line routines should
>be rare rather than typical. Average function length normally
>should be under 20 lines, and median length closer to 10. A
>length of 50 lines should normally be 95th percentile or better -
>anything worse is a strong indication that some refactoring is
>needed. Like what you said, I don't mean to make an arbitrary
>rule, but to give a useful empirical guideline for after-the-fact
>assessment.


My "limits" are a bit higher. I personally find sizes that low as
often forcing (or at least "strongly suggesting") decomposition
because you can, rather than because you should. Still, I'd say the
difference between a median of 10 and a median of 20 is more a quibble
than a qualitative change.

Tim Rentsch

unread,
Apr 5, 2018, 2:27:47 AM4/5/18
to
If you actually measured you might find the numbers are smaller
than you think. For example, I took the old BSD 'vi' sources and
ran statistics on them. With nearly 16,000 lines of source, and
just over 190 functions, the the median function length was 7
lines, the average just over 20, and the (only) 51 line function
coming in at 92+ percentile. And this happened despite there
being a dozen or so long functions, including eight over 80 lines,
the second-to-last of which about 125 lines, and the largest being
a whopping nearly 900 lines. The average and the median are small
not because there are no long functions but because there are lots
of little ones. Also there can be paradoxical effects - for
example if we took the 900 line function and split it into nine
functions of 100 lines each, the average would go down, but the
median would go up, and the percentile for 50 lines would also go
down.

The difference between a median of 10 and a median of 20 might
seem small quantatively, but if you looked at two code bases with
these median sizes I suspect you would find them to have vastly
different characters. For example, in another code base, with 60
lines being less than 90th percentile, and more than 20 functions
(out of 675 total) over 100 lines, the average was still only 24
lines, and the median 12. It would take a huge change to get that
median up to 20.

Paavo Helde

unread,
Apr 5, 2018, 1:30:01 PM4/5/18
to
On 5.04.2018 9:27, Tim Rentsch wrote:
>
> If you actually measured you might find the numbers are smaller
> than you think. For example, I took the old BSD 'vi' sources and
> ran statistics on them. With nearly 16,000 lines of source, and
> just over 190 functions, the the median function length was 7
> lines, the average just over 20, and the (only) 51 line function
> coming in at 92+ percentile.

Uh-oh. Just yesterday I had a code review of a 239-line function,
containing a 187-line lambda in the middle. The author was not happy at
all when I told him this is no good. He said he cannot think up names
for smaller functions and anyway he finds it easier to follow the
program logic if it is all nicely linear in a single function.

I am not hoping he will be making 10-line functions, our modest goal is
50 lines at the moment.

Cheers
Paavo




Richard

unread,
Apr 5, 2018, 3:38:04 PM4/5/18
to
[Please do not mail me a copy of your followup]

Paavo Helde <myfir...@osa.pri.ee> spake the secret code
<pa5mef$gnq$1...@dont-email.me> thusly:

>Uh-oh. Just yesterday I had a code review of a 239-line function,
>containing a 187-line lambda in the middle. The author was not happy at
>all when I told him this is no good. He said he cannot think up names
>for smaller functions and anyway he finds it easier to follow the
>program logic if it is all nicely linear in a single function.

So presumably he hates this example?
<https://www.industriallogic.com/xp/refactoring/composeMethod.html>

Vir Campestris

unread,
Apr 5, 2018, 4:35:22 PM4/5/18
to
On 05/04/2018 18:29, Paavo Helde wrote:
> I am not hoping he will be making 10-line functions, our modest goal is
> 50 lines at the moment.

50 is short. I aim to keep the entire function on screen. As screens
have grown from 25 lines my functions have grown a little too.

Andy
--
Work computer: 1600 pixels in portrait mode. Perhaps 100 lines?

Paavo Helde

unread,
Apr 5, 2018, 5:24:09 PM4/5/18
to
On 5.04.2018 22:37, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Paavo Helde <myfir...@osa.pri.ee> spake the secret code
> <pa5mef$gnq$1...@dont-email.me> thusly:
>
>> Uh-oh. Just yesterday I had a code review of a 239-line function,
>> containing a 187-line lambda in the middle. The author was not happy at
>> all when I told him this is no good. He said he cannot think up names
>> for smaller functions and anyway he finds it easier to follow the
>> program logic if it is all nicely linear in a single function.
>
> So presumably he hates this example?
> <https://www.industriallogic.com/xp/refactoring/composeMethod.html>

Not sure. Maybe. Or maybe not. He has never given a straight answer to
any questions I (or anybody else AFAIK) have asked, so in last years I
have stopped asking him anything.

To give him credits, he actually produces working code far from trivial,
albeit very slowly, and there are very few bugs in the final code. So,
if the code works, and there are no bugs, then why could it not be a
239-line function? I guess now he will spend the next 2 weeks on
refactoring this function into 50-line functions. I'm starting to doubt
my code review decisions...

Richard

unread,
Apr 5, 2018, 5:41:42 PM4/5/18
to
[Please do not mail me a copy of your followup]

Paavo Helde <myfir...@osa.pri.ee> spake the secret code
<pa645c$kja$1...@dont-email.me> thusly:

>To give him credits, he actually produces working code far from trivial,
>albeit very slowly, and there are very few bugs in the final code.

I too used to produce code this way before TDD. It's not that I
couldn't get the bugs out from careful manual testing, it's that the
time between creating the bug and fixing the bug was orders of
magnitude longer than when I practice TDD. In other words, my error
rate has remained rather consistent but the time between creating and
fixing a bug goes from never/months/weeks/days/hours to seconds.

>So,
>if the code works, and there are no bugs, then why could it not be a
>239-line function?

It's fine if it will never need to be modified ever again.

Robert Wessel

unread,
Apr 5, 2018, 5:57:29 PM4/5/18
to
On Thu, 05 Apr 2018 20:29:51 +0300, Paavo Helde
<myfir...@osa.pri.ee> wrote:

>On 5.04.2018 9:27, Tim Rentsch wrote:
>>
>> If you actually measured you might find the numbers are smaller
>> than you think. For example, I took the old BSD 'vi' sources and
>> ran statistics on them. With nearly 16,000 lines of source, and
>> just over 190 functions, the the median function length was 7
>> lines, the average just over 20, and the (only) 51 line function
>> coming in at 92+ percentile.
>
>Uh-oh. Just yesterday I had a code review of a 239-line function,
>containing a 187-line lambda in the middle. The author was not happy at
>all when I told him this is no good. He said he cannot think up names
>for smaller functions and anyway he finds it easier to follow the
>program logic if it is all nicely linear in a single function.


That raises an interesting philosophical point. Do you count lambdas
as a separate routine for the purposes of keeping routines a
reasonable number of lines? In languages that have traditionally
allowed nested functions, not counting the nested functions separately
would be absurd, and lambdas are looking more and more like nested
functions.

So in your example, is that a problematically long 239 line routine,
or an acceptable 52 line routine with a (problematically long) 187
line lambda? Leaving aside for a moment that any size goals for a
lambda probably ought to be considerably shorter that the usually "50
line" limit.

woodb...@gmail.com

unread,
Apr 5, 2018, 6:15:20 PM4/5/18
to
On Thursday, April 5, 2018 at 3:35:22 PM UTC-5, Vir Campestris wrote:
> On 05/04/2018 18:29, Paavo Helde wrote:
> > I am not hoping he will be making 10-line functions, our modest goal is
> > 50 lines at the moment.
>
> 50 is short. I aim to keep the entire function on screen. As screens
> have grown from 25 lines my functions have grown a little too.
>

Yeah, I'm happy when I find ways to get small functions, but don't
worry much about it when I can't figure out how to break up a big
function. I have a 114 line function here:
https://github.com/Ebenezer-group/onwards/blob/master/tiers/cmwA.cc

. It used to be longer so figure I'm making progress.


Brian
Ebenezer Enterprises
http://webEbenezer.net

Richard

unread,
Apr 5, 2018, 6:24:00 PM4/5/18
to
[Please do not mail me a copy of your followup]

Robert Wessel <robert...@yahoo.com> spake the secret code
<ke6dcddn12g6rst3o...@4ax.com> thusly:

>So in your example, is that a problematically long 239 line routine,
>or an acceptable 52 line routine with a (problematically long) 187
>line lambda?

The latter.

>Leaving aside for a moment that any size goals for a
>lambda probably ought to be considerably shorter that the usually "50
>line" limit.

There are legitimate reasons for having large-ish lambdas. James
McNellis and Kate Gregory go over a use case for large-ish lambdas in
their "Modernizing Legacy C++ Code" talk here:
<https://www.youtube.com/watch?v=LDxAgMe6D18#t=29m17s>

Paavo Helde

unread,
Apr 6, 2018, 1:14:13 AM4/6/18
to
The line limit comes from the desire to fit the whole function to the
screen at the same time. In our typical development environment this is
indeed ca 50 lines. Of course there are exceptions, if I have a switch
with 200 cases I should better forget about the line limit.

I believe in languages with nested functions they have some code clarity
rules to place the nested functions in the beginning or in the end of
the parent function, so that the parent function code could be seen
together on the screen. The problem with lambdas is that they must be
placed in the middle of the parent function, disrupting it. So I would
say there is a problem with both the 187 line lambda and the 52 line
parent function, neither can be fit to the screen (either too long or
disjoint).





Paavo Helde

unread,
Apr 6, 2018, 1:25:18 AM4/6/18
to
On 6.04.2018 0:41, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Paavo Helde <myfir...@osa.pri.ee> spake the secret code
> <pa645c$kja$1...@dont-email.me> thusly:
>
>> To give him credits, he actually produces working code far from trivial,
>> albeit very slowly, and there are very few bugs in the final code.
>
> I too used to produce code this way before TDD. It's not that I
> couldn't get the bugs out from careful manual testing, it's that the
> time between creating the bug and fixing the bug was orders of
> magnitude longer than when I practice TDD. In other words, my error
> rate has remained rather consistent but the time between creating and
> fixing a bug goes from never/months/weeks/days/hours to seconds.

His work also involves creating unit tests for everything he writes, so
I have assumed he uses TDD at least to some extent (with D=Development,
not Design - side note to Mr Flibble). But coming to think of that I'm
not so sure any more. Maybe he considers a failing test as a personal
insult even if no one else sees it, and does not dare to run the test
before he is 100% sure it will succeed.

Vir Campestris

unread,
Apr 6, 2018, 3:55:27 PM4/6/18
to
On 06/04/2018 06:14, Paavo Helde wrote:
> The problem with lambdas is that they must be placed in the middle of
> the parent function, disrupting it.

They don't _have_ to be. You can declare them elsewhere - though often
they can then be an ordinary function instead.

Andy

Cholo Lennon

unread,
Apr 6, 2018, 4:33:14 PM4/6/18
to
On 28/02/18 21:57, JiiPee wrote:
> Sorry first message was a mess, so reposting it:
>
> for (int i = 0; i < m; i++) {
>     for (int j = 0; j < n; j++) {
>          if (some condition) {
>              // Do something and break...
>              goto afterLoop; // Breaks out of both loops
>          }
>     }
> }
> afterLoop:
>
> I googled and this seems to be manys preferably way. I have this often.
> How would you break nested loops? Somebody said Substroup said this is ok.

Agreed. This is the one of a few situations where I use a goto (I also
use it with a switch inside a loop), and IMHO it's the best option if
you have some code after the label (otherwise as others have said, use
return instead of goto)


--
Cholo Lennon
Bs.As.
ARG
It is loading more messages.
0 new messages