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

Simple Program from 2.3.2 of Stroustrup 3/e

186 views
Skip to first unread message

arnuld

unread,
Jan 11, 2018, 11:14:34 PM1/11/18
to
I have been out of coding for few years and out of C++ for more than few.
I hope few of you remembered me :) . Wanted to get back to the
fundamentals of good C++ practices. Here is a bit modified program from
section 2.3.2 of Stroustrup's 3/e of book The C++ Programming Language.
It works fine, any advice will be appreciated:



#include <iostream>

bool askSample();


int main()
{
while(askSample())
;

return 0;
}


bool askSample()
{
std::cout << "Do you want to prceed (y/n) ? " << std::endl;
char answer = 0;
std::cin >> answer;

if('y' == answer)
return true;
else if('n' == answer)
return false;
else
{
std::cout << "Only 'y' or 'n' please" << std::endl;
return true;
}
}
======================= OUTPUT ==============================
[arnuld@arch64 programs]$ g++ -std=c++17 -pedantic -Wall -Wextra 232.cpp
[arnuld@arch64 programs]$ ./a.out
Do you want to prceed (y/n) ?
y
Do you want to prceed (y/n) ?
p
Only 'y' or 'n' please
Do you want to prceed (y/n) ?
n
[arnuld@arch64 programs]$



--
-- arnuld
http://lispmachine.wordpress.com/

David Brown

unread,
Jan 13, 2018, 6:49:08 AM1/13/18
to
On 12/01/18 17:44, Stefan Ram wrote:
> arnuld <sun...@invalid.address> writes:
>> bool askSample();
>
> #include <iostream>
> #include <istream>
> #include <limits>
> #include <ostream>
>
> static bool askSample()
> { while( true )
> { ::std::cout << "Do you want to proceed (y/n) ?\n";
> char answer = 0;
> std::cin >> answer;
> if( 'y' == answer || 'Y' == answer )return true;
> if( 'n' == answer || 'N' == answer )return false;
> std::cout << "Only 'y' or 'n' please!" << std::endl;
> ::std::cin.clear();
> ::std::cin.ignore
> ( ::std::numeric_limits< ::std::streamsize >::max(), '\n' ); }}
>
> int main(){ while( askSample() ); }
>

I cannot grasp the mentality that would make someone think this is a
clear way to write code - and certainly not why you think it might help
a relative beginner who asks for an advice. He asked for advice - not a
re-write in an incomprehensible style that is unique to you.

If you really want to help people, write your code in a style that is
commonly used by programmers, books, websites, etc. And if you want to
give the OP advice, don't re-do his code in a weird style - explain why
you think the calls to clear() and ignore() are important.

Personally, I think the original code was fine for the task.

Jorgen Grahn

unread,
Jan 14, 2018, 8:55:38 AM1/14/18
to
On Fri, 2018-01-12, arnuld wrote:
> I have been out of coding for few years and out of C++ for more than few.
> I hope few of you remembered me :) . Wanted to get back to the
> fundamentals of good C++ practices.

Whatever /those/ are ...

> Here is a bit modified program from
> section 2.3.2 of Stroustrup's 3/e of book The C++ Programming Language.
> It works fine, any advice will be appreciated:
>
>
>
> #include <iostream>
>
> bool askSample();

I'd place the implementation of askSample() here, in an anonymous
namespace. People probably think differently about it, but I really
dislike forward declarations; I'm much happier with having functions
(and other things) appear just when they're needed -- even though that
means main() as to come last.

> int main()
> {
> while(askSample())
> ;
>
> return 0;
> }
>
>
> bool askSample()
> {
> std::cout << "Do you want to prceed (y/n) ? " << std::endl;

Unrelated to C++, but that kind of prompting is almost always the
wrong user interface for a real program.

> char answer = 0;
> std::cin >> answer;
>
> if('y' == answer)
> return true;
> else if('n' == answer)
> return false;
> else
> {
> std::cout << "Only 'y' or 'n' please" << std::endl;
> return true;
> }
> }
> ======================= OUTPUT ==============================
> [arnuld@arch64 programs]$ g++ -std=c++17 -pedantic -Wall -Wextra 232.cpp

You use the same warning options as me, so I obviously approve ;-)

IMHO, since you seem to be on Unix, you should write a Makefile. This
would do for your case, I think:

CXXFLAGS=-std=c++17 -pedantic -Wall -Wextra
a.out: 232.o
$(CXX) $(CXXFLAGS) -o $@ $<

/Jorgen

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

David Brown

unread,
Jan 14, 2018, 4:39:28 PM1/14/18
to
On 14/01/18 14:55, Jorgen Grahn wrote:
> On Fri, 2018-01-12, arnuld wrote:
>> I have been out of coding for few years and out of C++ for more than few.
>> I hope few of you remembered me :) . Wanted to get back to the
>> fundamentals of good C++ practices.
>
> Whatever /those/ are ...
>
>> Here is a bit modified program from
>> section 2.3.2 of Stroustrup's 3/e of book The C++ Programming Language.
>> It works fine, any advice will be appreciated:
>>
>>
>>
>> #include <iostream>
>>
>> bool askSample();
>
> I'd place the implementation of askSample() here, in an anonymous
> namespace. People probably think differently about it, but I really
> dislike forward declarations; I'm much happier with having functions
> (and other things) appear just when they're needed -- even though that
> means main() as to come last.
>

I think the same as you - I prefer to order my code as bottom-up. And
it should definitely be in an anonymous namespace or "static" (static is
perhaps a bit old-fashioned).

Jorgen Grahn

unread,
Jan 15, 2018, 1:58:12 AM1/15/18
to
On Sun, 2018-01-14, David Brown wrote:
> On 14/01/18 14:55, Jorgen Grahn wrote:
>> On Fri, 2018-01-12, arnuld wrote:
>>> I have been out of coding for few years and out of C++ for more than few.
>>> I hope few of you remembered me :) . Wanted to get back to the
>>> fundamentals of good C++ practices.
>>
>> Whatever /those/ are ...
>>
>>> Here is a bit modified program from
>>> section 2.3.2 of Stroustrup's 3/e of book The C++ Programming Language.
>>> It works fine, any advice will be appreciated:
>>>
>>>
>>>
>>> #include <iostream>
>>>
>>> bool askSample();
>>
>> I'd place the implementation of askSample() here, in an anonymous
>> namespace. People probably think differently about it, but I really
>> dislike forward declarations; I'm much happier with having functions
>> (and other things) appear just when they're needed -- even though that
>> means main() as to come last.
>>
>
> I think the same as you - I prefer to order my code as bottom-up.

Maybe it's the most common way to do it by now. I also find that it
helps encourage me to split out helper functions and classes.

Speaking about helper functions, does anyone use lambdas as local
helper functions these days? Like:

void foo(Arg arg)
{
...
auto bar = [&arg]() { ... };
...
// use bar()
}

where bar() is used for brevity and readability only, not as e.g. a
predicate. Sorry about the synthetic example.

I tend to do this in Python, and am beginning to do it in C++ too.

> And it should definitely be in an anonymous namespace or "static"
> (static is perhaps a bit old-fashioned).

I count static for this scenario as clearly old-fashioned; I think
Stroustrup said so in his TC++PL 20 years ago.

Ian Collins

unread,
Jan 15, 2018, 3:08:01 AM1/15/18
to
On 01/15/2018 07:57 PM, Jorgen Grahn wrote:
> On Sun, 2018-01-14, David Brown wrote:>>>
>>
>> I think the same as you - I prefer to order my code as bottom-up.
>
> Maybe it's the most common way to do it by now. I also find that it
> helps encourage me to split out helper functions and classes.
>
> Speaking about helper functions, does anyone use lambdas as local
> helper functions these days? Like:
>
> void foo(Arg arg)
> {
> ...
> auto bar = [&arg]() { ... };
> ...
> // use bar()
> }
>
> where bar() is used for brevity and readability only, not as e.g. a
> predicate. Sorry about the synthetic example.

I just happed to have written something similar today:

auto error = [this]( std::string function )
{
LOG_ERROR(("Open: "+function+" failed %s").c_str(), strerror(errno));
close(m_SocketFd);
m_SocketFd = kInvalidFd;
return false;
};

for use in a function (in code that does not use exceptions) that has a
number of operations on a socket like

if (bind(m_SocketFd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
return error("bind");
}

--
Ian.

Jorgen Grahn

unread,
Jan 15, 2018, 8:13:38 AM1/15/18
to
Thanks! That's more or less the non-synthetic example I wanted to give.

Alf P. Steinbach

unread,
Jan 15, 2018, 9:35:11 AM1/15/18
to
Here's another example:

https://github.com/alf-p-steinbach/NPP-plugin-Empty-files-as-Unicode/blob/d16829ea2025fb0c60eec01ee97bc1be40934f9d/source/plugin/Plugin.hpp#L124

void update_menus()
{
using Static_id = menu::Static_cmd_id;
const auto set_item_check = [&]( const Static_id::Enum i,
const bool value )
{
npp_.set_menu_item_check( menu::dynamic_cmd_id( i ),
value );
};

set_item_check( Static_id::set_enabled, not is_disabled_ );
set_item_check( Static_id::set_disabled, is_disabled_ );
}


Cheers!,

- Alf

Mr Flibble

unread,
Jan 15, 2018, 12:25:38 PM1/15/18
to
Modulo "m_" why do you choose the worst naming convention possible of
mixed case AND underscores IN THE SAME SYMBOL? Egregious.

/Flibble

--
"Suppose it’s all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I’d say, bone cancer in children? What’s that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It’s not right, it’s utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates
a world that is so full of injustice and pain. That’s what I would say."

Ian Collins

unread,
Jan 15, 2018, 1:55:30 PM1/15/18
to
On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:

>
> Here's another example:
>
> void update_menus()
> {
> using Static_id = menu::Static_cmd_id;
> const auto set_item_check = [&]( const Static_id::Enum i,
> const bool value )

Why did you const qualify the parameters?

--
Ian

Alf P. Steinbach

unread,
Jan 15, 2018, 5:37:20 PM1/15/18
to
I think you mean to ask about the rationale of the naming convention.

It is of course the goodest on Earth. ;-)

The trailing underscore for member names is short and doesn't conflict
with the various rules for reserved names. It's the convention used in
Boost.

Underscores as word separators are nice in Windows programming. It's
easy to see that they're not Microsoft symbols. Also they're generally
much more clear and readable, IMHO, than PascalCase.

Leading uppercase for a type name makes it easy to identify types as
such, and lets you have a type and a variable with same name in the
admittedly very few cases where it's unnatural to invent other names.

The only reason I can think of for not combining those desirable traits
would be that it's currently somewhat unconventional. I guess that's
where your “worst” and “egregious” come from, gut reactions to seeing
something unfamiliar. But objectively it's a good combination. ;-)


Cheers & hth.,

- Alf

Mr Flibble

unread,
Jan 15, 2018, 5:43:54 PM1/15/18
to
Speaking "objectively" that is simply your opinion. You are correct it
is unconventional and it is unconventional for a reason: egregiousness.

Now reply to Ian to explain your egregious const qualified function
parameter clusterfuck.

Alf P. Steinbach

unread,
Jan 15, 2018, 5:45:33 PM1/15/18
to
The rationale for `const` on formal arguments in a function definition
is the same as the rationale for `const` on local variables, and vice versa.

Mainly that it, in the general case, constrains the possible effects of
the code, so that the code is easier to grok and reason about.

It's something that I do automatically unless there is a very good
reason to not do it, for about the same reason that a car driver signals
her intended direction at a cross-roads even where there are no other
cars or people, and would need to decide very positively to not do it.


Cheers!,

- Alf

Ian Collins

unread,
Jan 15, 2018, 5:52:55 PM1/15/18
to
On 01/16/2018 11:45 AM, Alf P. Steinbach wrote:
> On 1/15/2018 7:55 PM, Ian Collins wrote:
>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>
>>>
>>> Here's another example:
>>>
>>>           void update_menus()
>>>           {
>>>               using Static_id = menu::Static_cmd_id;
>>>               const auto set_item_check = [&]( const Static_id::Enum i,
>>> const bool value )
>>
>> Why did you const qualify the parameters?
>
> The rationale for `const` on formal arguments in a function definition
> is the same as the rationale for `const` on local variables, and vice versa.
>
> Mainly that it, in the general case, constrains the possible effects of
> the code, so that the code is easier to grok and reason about.

Um, you are probably in a small minority there. To my eyes they are
just clutter. In our code base I remove spurious parameter qualifiers
almost as zealously as I remove passing integral types by const reference!

> It's something that I do automatically unless there is a very good
> reason to not do it, for about the same reason that a car driver signals
> her intended direction at a cross-roads even where there are no other
> cars or people, and would need to decide very positively to not do it.

A better analogy would be using hazard lights to indicate driving
straight...

--
Ian.

Alf P. Steinbach

unread,
Jan 15, 2018, 5:59:23 PM1/15/18
to
On 1/15/2018 11:52 PM, Ian Collins wrote:
> On 01/16/2018 11:45 AM, Alf P. Steinbach wrote:
>> On 1/15/2018 7:55 PM, Ian Collins wrote:
>>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>>
>>>>
>>>> Here's another example:
>>>>
>>>>            void update_menus()
>>>>            {
>>>>                using Static_id = menu::Static_cmd_id;
>>>>                const auto set_item_check = [&]( const
>>>> Static_id::Enum i,
>>>> const bool value )
>>>
>>> Why did you const qualify the parameters?
>>
>> The rationale for `const` on formal arguments in a function definition
>> is the same as the rationale for `const` on local variables, and vice
>> versa.
>>
>> Mainly that it, in the general case, constrains the possible effects of
>> the code, so that the code is easier to grok and reason about.
>
> Um, you are probably in a small minority there.  To my eyes they are
> just clutter.  In our code base I remove spurious parameter qualifiers
> almost as zealously as I remove passing integral types by const reference!

One can make a case for that, e.g. that it supports move semantics by
default.

But I value default `const`-ness as support for correctness, more than I
value default mutability as support for that optimization.

So, different choices. ;-)


[snip]

Mr Flibble

unread,
Jan 15, 2018, 6:01:13 PM1/15/18
to
On 15/01/2018 22:45, Alf P. Steinbach wrote:
> On 1/15/2018 7:55 PM, Ian Collins wrote:
>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>
>>>
>>> Here's another example:
>>>
>>>           void update_menus()
>>>           {
>>>               using Static_id = menu::Static_cmd_id;
>>>               const auto set_item_check = [&]( const Static_id::Enum i,
>>> const bool value )
>>
>> Why did you const qualify the parameters?
>
> The rationale for `const` on formal arguments in a function definition
> is the same as the rationale for `const` on local variables, and vice
> versa.
>
> Mainly that it, in the general case, constrains the possible effects of
> the code, so that the code is easier to grok and reason about.

Reason about wrongly you mean: making the function *parameter* const may
lead you to have the false impression that the function *argument* that
was copied to it was also const or a constant when in fact it was a
variable.

IMO this, like most of your other idioms, obfuscates rather then elucidates.

Ian Collins

unread,
Jan 15, 2018, 6:39:12 PM1/15/18
to
On 01/16/2018 11:59 AM, Alf P. Steinbach wrote:
> On 1/15/2018 11:52 PM, Ian Collins wrote:
>> On 01/16/2018 11:45 AM, Alf P. Steinbach wrote:
>>> On 1/15/2018 7:55 PM, Ian Collins wrote:
>>>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>>>
>>>>>
>>>>> Here's another example:
>>>>>
>>>>>            void update_menus()
>>>>>            {
>>>>>                using Static_id = menu::Static_cmd_id;
>>>>>                const auto set_item_check = [&]( const
>>>>> Static_id::Enum i,
>>>>> const bool value )
>>>>
>>>> Why did you const qualify the parameters?
>>>
>>> The rationale for `const` on formal arguments in a function definition
>>> is the same as the rationale for `const` on local variables, and vice
>>> versa.
>>>
>>> Mainly that it, in the general case, constrains the possible effects of
>>> the code, so that the code is easier to grok and reason about.
>>
>> Um, you are probably in a small minority there.  To my eyes they are
>> just clutter.  In our code base I remove spurious parameter qualifiers
>> almost as zealously as I remove passing integral types by const reference!
>
> One can make a case for that, e.g. that it supports move semantics by
> default.

Move semantics on an int?

> But I value default `const`-ness as support for correctness, more than I
> value default mutability as support for that optimization.

How often have you seen code which modifies a value parameter? I guess
you could say that they have implied constness...

I still like my hazard lights analogy :)

--
Ian.

Alf P. Steinbach

unread,
Jan 15, 2018, 6:41:41 PM1/15/18
to
On 1/16/2018 12:01 AM, Mr Flibble wrote:
> On 15/01/2018 22:45, Alf P. Steinbach wrote:
>> On 1/15/2018 7:55 PM, Ian Collins wrote:
>>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>>
>>>>
>>>> Here's another example:
>>>>
>>>>           void update_menus()
>>>>           {
>>>>               using Static_id = menu::Static_cmd_id;
>>>>               const auto set_item_check = [&]( const Static_id::Enum i,
>>>> const bool value )
>>>
>>> Why did you const qualify the parameters?
>>
>> The rationale for `const` on formal arguments in a function definition
>> is the same as the rationale for `const` on local variables, and vice
>> versa.
>>
>> Mainly that it, in the general case, constrains the possible effects
>> of the code, so that the code is easier to grok and reason about.
>
> Reason about wrongly you mean: making the function *parameter* const may
> lead you to have the false impression that the function *argument* that
> was copied to it was also const or a constant when in fact it was a
> variable.

There's nothing in the C++ language that could lead to such confusion.

At best you're talking about writing code that will be roughly
understood by people who could mistake a green apple for a broccoli on
account of the similar color, and supporting such people is not my goal.

Good luck with that.


> IMO this, like most of your other idioms, obfuscates rather then
> elucidates.


Cheers!,

- Alf

Alf P. Steinbach

unread,
Jan 15, 2018, 6:45:00 PM1/15/18
to
I don't think you actually failed to understand what a default
convention is about.


>> But I value default `const`-ness as support for correctness, more than I
>> value default mutability as support for that optimization.
>
> How often have you seen code which modifies a value parameter?  I guess
> you could say that they have implied constness...
>
> I still like my hazard lights analogy :)

Because it's nothing but an associative label.

Mr Flibble

unread,
Jan 15, 2018, 7:03:48 PM1/15/18
to
On 15/01/2018 23:41, Alf P. Steinbach wrote:
> On 1/16/2018 12:01 AM, Mr Flibble wrote:
>> On 15/01/2018 22:45, Alf P. Steinbach wrote:
>>> On 1/15/2018 7:55 PM, Ian Collins wrote:
>>>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>>>
>>>>>
>>>>> Here's another example:
>>>>>
>>>>>           void update_menus()
>>>>>           {
>>>>>               using Static_id = menu::Static_cmd_id;
>>>>>               const auto set_item_check = [&]( const
>>>>> Static_id::Enum i,
>>>>> const bool value )
>>>>
>>>> Why did you const qualify the parameters?
>>>
>>> The rationale for `const` on formal arguments in a function
>>> definition is the same as the rationale for `const` on local
>>> variables, and vice versa.
>>>
>>> Mainly that it, in the general case, constrains the possible effects
>>> of the code, so that the code is easier to grok and reason about.
>>
>> Reason about wrongly you mean: making the function *parameter* const
>> may lead you to have the false impression that the function *argument*
>> that was copied to it was also const or a constant when in fact it was
>> a variable.
>
> There's nothing in the C++ language that could lead to such confusion.

Correct; it is your use of said language that is the problem.

>
> At best you're talking about writing code that will be roughly
> understood by people who could mistake a green apple for a broccoli on
> account of the similar color, and supporting such people is not my goal.
>
> Good luck with that.

The goal should be for code to be as easy to understand as possible at
both the micro and macro level; at both the call site and the callee
site. Your idioms do the opposite: they obfuscate making code harder to
reason about.

Melzzzzz

unread,
Jan 15, 2018, 7:25:18 PM1/15/18
to
I use objects and classes defined in function for that, as I am still on
C++98 ;)

--
press any key to continue or any other to quit...

Melzzzzz

unread,
Jan 15, 2018, 7:26:47 PM1/15/18
to
Well, sure I rememeber good, that declaring function as void f(const int n)
for example is anti pattern ;p

>
> /Flibble

Ian Collins

unread,
Jan 15, 2018, 7:37:41 PM1/15/18
to
On 01/16/2018 01:25 PM, Melzzzzz wrote:
>
> I use objects and classes defined in function for that, as I am still on
> C++98 ;)

Time to cut the shackles!

--
Ian.

Alf P. Steinbach

unread,
Jan 15, 2018, 7:38:18 PM1/15/18
to
Nobody confuses actual argument constness with formal argument constness.

The term “programmer” would not apply to such a person. Maybe you're
talking about a child of age 7, or someone with an extreme head injury.
Your stipulation of writing code for such a person can be nothing but
trolling, but I choose to answer you seriously.

Anyway, for someone confusing formal argument constness with actual
argument constness, your convention of non-const formal argument would
likewise, incorrectly, imply non-const actual argument.

No coding convention can save the 8-year old child, or the head injured,
from mis-interpreting your code, in the way that you describe.


>  Your idioms do the opposite: they obfuscate making code harder to
> reason about.

The `const` on a local variable or formal argument isn't an indication
of constness of the source of the value.

It's a constraint, saying that this value won't be changing.

Mr Flibble

unread,
Jan 15, 2018, 7:41:15 PM1/15/18
to
On 16/01/2018 00:38, Alf P. Steinbach wrote:
>
> The `const` on a local variable or formal argument isn't an indication
> of constness of the source of the value.
>
> It's a constraint, saying that this value won't be changing.

It is superfluous because as the parameter is a value copy changes to it
would have no side effects (certainly for scalar types). It is
obfuscation pure and simple. No need for it.

Ian Collins

unread,
Jan 15, 2018, 7:48:39 PM1/15/18
to
On 01/16/2018 01:38 PM, Alf P. Steinbach wrote:
>
> The `const` on a local variable or formal argument isn't an indication
> of constness of the source of the value.
>
> It's a constraint, saying that this value won't be changing.

While true, it is pretty much superfluous and it isn't idiomatic which
makes the ready think twice. As I said up thread, how often have you
seen code which modifies a value parameter?

--
Ian.

Alf P. Steinbach

unread,
Jan 15, 2018, 7:50:56 PM1/15/18
to
On 1/16/2018 1:41 AM, Mr Flibble wrote:
> On 16/01/2018 00:38, Alf P. Steinbach wrote:
>>
>> The `const` on a local variable or formal argument isn't an indication
>> of constness of the source of the value.
>>
>> It's a constraint, saying that this value won't be changing.
>
> It is superfluous because as the parameter is a value copy changes to it
> would have no side effects (certainly for scalar types).

You're IMO partially right here, but if so then for the wrong reason.

In the concrete example (up-thread) the `const` is, IMO, indeed
superfluous, because the function body is just a single function call.

But in general the top level `const` on pass-by-value formal argument is
a constraint on what can happen to that value in the function's code,
e.g. when that code is a loop with not grokable-at-a-glance body. It is
not intended as a constraint on what can happen to the actual argument.
I apply the `const` as a general default that supports correctness,
where its absence signals that that formal argument needs to be mutable.


>  It is obfuscation pure and simple. No need for it.

Mr Flibble

unread,
Jan 15, 2018, 7:56:24 PM1/15/18
to
On 16/01/2018 00:50, Alf P. Steinbach wrote:
> On 1/16/2018 1:41 AM, Mr Flibble wrote:
>> On 16/01/2018 00:38, Alf P. Steinbach wrote:
>>>
>>> The `const` on a local variable or formal argument isn't an
>>> indication of constness of the source of the value.
>>>
>>> It's a constraint, saying that this value won't be changing.
>>
>> It is superfluous because as the parameter is a value copy changes to
>> it would have no side effects (certainly for scalar types).
>
> You're IMO partially right here, but if so then for the wrong reason.
>
> In the concrete example (up-thread) the `const` is, IMO, indeed
> superfluous, because the function body is just a single function call.

There is no difference between

int f(int a, int b)
{
return add(a, b);
}

and

int f(int a, int b)
{
return a + b;
}

as to whether or not a const qualification of the function parameters
would be superfluous. It would be superfluous in both cases.

Cheers & I hope this fucking helps.,

- Flibble

Melzzzzz

unread,
Jan 15, 2018, 7:57:10 PM1/15/18
to
Heh, not me ;)

Alf P. Steinbach

unread,
Jan 15, 2018, 7:59:31 PM1/15/18
to
It happens. E.g., the common swap idiom for exception safe assignment,

auto operator=( Self other )
-> Self
{ swap( *this, other ); }

Of course it can be written less succinctly with `const` formal argument:

auto operator=( Self const& other )
-> Self
{
Self temp = other;
swap( *this, temp );
}

But this version is not just more verbose: disregarding the compiler's
likely optimization it's less efficient for the case of rvalue argument.

Mr Flibble

unread,
Jan 15, 2018, 8:04:33 PM1/15/18
to
Both versions exhibit undefined behaviour probably due to over
confidence caused by your egregious non-idiomatic "auto" return type OCD.

Melzzzzz

unread,
Jan 15, 2018, 8:08:35 PM1/15/18
to
On 2018-01-16, Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> On 16/01/2018 00:59, Alf P. Steinbach wrote:
>> On 1/16/2018 1:48 AM, Ian Collins wrote:
>>> On 01/16/2018 01:38 PM, Alf P. Steinbach wrote:
>>>>
>>>> The `const` on a local variable or formal argument isn't an indication
>>>> of constness of the source of the value.
>>>>
>>>> It's a constraint, saying that this value won't be changing.
>>>
>>> While true, it is pretty much superfluous and it isn't idiomatic which
>>> makes the ready think twice.  As I said up thread, how often have you
>>> seen code which modifies a value parameter?
>>
>> It happens. E.g., the common swap idiom for exception safe assignment,
>>
>>     auto operator=( Self other )
>>         -> Self
>>     { swap( *this, other ); }
>>
>> Of course it can be written less succinctly with `const` formal argument:
>>
>>     auto operator=( Self const& other )
>>         -> Self
>>     {
>>         Self temp = other;
>>         swap( *this, temp );
>>     }
>>
>> But this version is not just more verbose: disregarding the compiler's
>> likely optimization it's less efficient for the case of rvalue argument.
>
> Both versions exhibit undefined behaviour probably due to over
> confidence caused by your egregious non-idiomatic "auto" return type OCD.

Yeah, operator = shoudl return reference to this or some lhs object ;)
>
> /Flibble

Alf P. Steinbach

unread,
Jan 15, 2018, 8:42:57 PM1/15/18
to
On 1/16/2018 2:04 AM, Mr Flibble wrote:
> On 16/01/2018 00:59, Alf P. Steinbach wrote:
>> On 1/16/2018 1:48 AM, Ian Collins wrote:
>>> On 01/16/2018 01:38 PM, Alf P. Steinbach wrote:
>>>>
>>>> The `const` on a local variable or formal argument isn't an indication
>>>> of constness of the source of the value.
>>>>
>>>> It's a constraint, saying that this value won't be changing.
>>>
>>> While true, it is pretty much superfluous and it isn't idiomatic
>>> which makes the ready think twice.  As I said up thread, how often
>>> have you seen code which modifies a value parameter?
>>
>> It happens. E.g., the common swap idiom for exception safe assignment,
>>
>>      auto operator=( Self other )
>>          -> Self
>>      { swap( *this, other ); }
>>
>> Of course it can be written less succinctly with `const` formal argument:
>>
>>      auto operator=( Self const& other )
>>          -> Self
>>      {
>>          Self temp = other;
>>          swap( *this, temp );
>>      }
>>
>> But this version is not just more verbose: disregarding the compiler's
>> likely optimization it's less efficient for the case of rvalue argument.
>
> Both versions exhibit undefined behaviour probably due to over
> confidence caused by your egregious non-idiomatic "auto" return type OCD.

No, it has nothing to do with `auto` (the function declaration syntax).

But I forgot a `&` there, it should be

-> Self&

and there should be a

return *this;

at the end of each function.

Those are silly errors from posting an answer overly quickly, and I'd
like to thank you for pointing it out, even with the added misleading
assertion. I tend to rely on Thunderbird 2036b's automatic check of
posting contents, but it's not yet been implemented. Thanks. :)

Cheers!,

- Alf

Ian Collins

unread,
Jan 15, 2018, 8:56:05 PM1/15/18
to
If you are going to use auto, you don't need the suffix return in this
case :)

--
Ian.

Jorgen Grahn

unread,
Jan 16, 2018, 2:06:07 AM1/16/18
to
On Mon, 2018-01-15, Ian Collins wrote:
> On 01/16/2018 11:45 AM, Alf P. Steinbach wrote:
>> On 1/15/2018 7:55 PM, Ian Collins wrote:
>>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>>
>>>>
>>>> Here's another example:
>>>>
>>>>           void update_menus()
>>>>           {
>>>>               using Static_id = menu::Static_cmd_id;
>>>>               const auto set_item_check = [&]( const Static_id::Enum i,
>>>> const bool value )
>>>
>>> Why did you const qualify the parameters?
>>
>> The rationale for `const` on formal arguments in a function definition
>> is the same as the rationale for `const` on local variables, and vice versa.
>>
>> Mainly that it, in the general case, constrains the possible effects of
>> the code, so that the code is easier to grok and reason about.
>
> Um, you are probably in a small minority there. To my eyes they are
> just clutter. In our code base I remove spurious parameter qualifiers
> almost as zealously as I remove passing integral types by const reference!

Oddly, I'm with Alf here. Maybe not for tiny function bodies like this one,
but not just for huge ones either.

To me, /not/ marking them 'const' signals an intent to modify them
later on in the code.

How common that view is, I cannot tell. It has been uncontroversial
where I worked. Perhaps I've done it more than others, but I can't
recall having problems with it in my code reviews.

/Jorgen

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

Jorgen Grahn

unread,
Jan 16, 2018, 2:16:15 AM1/16/18
to
On Tue, 2018-01-16, Melzzzzz wrote:
> On 2018-01-15, Jorgen Grahn <grahn...@snipabacken.se> wrote:
...
>> Speaking about helper functions, does anyone use lambdas as local
>> helper functions these days? Like:
>>
>> void foo(Arg arg)
>> {
>> ...
>> auto bar = [&arg]() { ... };
>> ...
>> // use bar()
>> }
>>
>> where bar() is used for brevity and readability only, not as e.g. a
>> predicate. Sorry about the synthetic example.
>
> I use objects and classes defined in function for that, as I am still on
> C++98 ;)

Yeah, I tried to do that, too, but my point was that you can do it
better now.

E.g., I was always hesitant to add a private member function
Foo::baz() when I just wanted to tidy up the implementation of
Foo::bar().

As for predicates, it was famously clumpsy to write a small class with
operator() just for one call to std::remove_if() or similar.

Öö Tiib

unread,
Jan 16, 2018, 2:38:01 AM1/16/18
to
Looking at couple code bases I see sometimes algorithms to what iterators
are passed. Those more often iterate using iterator parameters instead
of making additional local copies.

There are clear benefits of being conservative but there are also
benefits of being innovative. For example thanks to Alf's attempts of
innovation we have something to discuss and to think twice. ;)

James Kuyper

unread,
Jan 16, 2018, 8:47:30 AM1/16/18
to
I treat value parameters the same as any other local variable - which
means it's not particularly uncommon for my code to modify them. For
precisely the same reason, I declare them const according to the same
policy I use for other local variables: they are const by default unless
I plan to modify them.

Vir Campestris

unread,
Jan 16, 2018, 4:05:10 PM1/16/18
to
On 16/01/2018 13:47, James Kuyper wrote:
> I treat value parameters the same as any other local variable - which
> means it's not particularly uncommon for my code to modify them. For
> precisely the same reason, I declare them const according to the same
> policy I use for other local variables: they are const by default unless
> I plan to modify them.

Another vote for const here. You never know, it might help the compiler...

Where I'll disagree with Alf is on auto. I use it only when I have to -
for example, lambdas. I don't think it adds clarity.

Sure, my GUI will (usually) tell me the type if I hover on it. But I
have to move the mouse, not my eyes, and my eyes are faster.

Andy

Ian Collins

unread,
Jan 16, 2018, 8:52:15 PM1/16/18
to
On 01/17/2018 12:58 PM, Stefan Ram wrote:
> James Kuyper <james...@verizon.net> writes:
>> I treat value parameters the same as any other local variable - which
>> means it's not particularly uncommon for my code to modify them. For
>> precisely the same reason, I declare them const according to the same
>> policy I use for other local variables: they are const by default unless
>> I plan to modify them.
>
> “Use const whenever possible.”
>
> Scott Meyers
>
> “Use const to define objects with values
> that do not change after construction ”
>
> C++ Core Guideline; April 7, 2016;
> Bjarne Stroustrup and Herb Sutter

Function parameter types aren't defined objects.

--
Ian.

Richard

unread,
Jan 16, 2018, 9:11:54 PM1/16/18
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<fc7oi0...@mid.individual.net> thusly:
I think there's also a guideline that says not to modify function
parameters.
--
"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>

James Kuyper

unread,
Jan 16, 2018, 10:37:10 PM1/16/18
to
Well, strictly speaking that's correct, types in general are not
objects. I presume you meant that function parameters are not defined
objects? By what argument?

asetof...@gmail.com

unread,
Jan 17, 2018, 8:39:12 AM1/17/18
to
One can pass obj to a function using pointers or References

Gareth Owen

unread,
Jan 17, 2018, 4:48:07 PM1/17/18
to
Ian Collins <ian-...@hotmail.com> writes:

> How often have you seen code which modifies a value parameter?

Very occasionally in things like

void do_something_n_times(int n)
{
while(n--) {
do_something_once();
}
}

asetof...@gmail.com

unread,
Jan 18, 2018, 4:22:21 AM1/18/18
to
In
void do_something_n_times(int n)
{
while(n--) {
do_something_once();
}
}
Is not modified parameter is modified one copy of it...
This modify the parameters
void do_something_n_times(int& n)
{
while(n--) {
do_something_once();
}
}

But I do it never...
For modify parameter I use pointer so it is seen to the caller the function modify its parameter
void do_something_n_times(int* n)
{
while((*n)--) {
do_something_once();
}
}

Tim Rentsch

unread,
Jan 24, 2018, 4:25:02 PM1/24/18
to
Jorgen Grahn <grahn...@snipabacken.se> writes:

> On Mon, 2018-01-15, Ian Collins wrote:
>
>> On 01/16/2018 11:45 AM, Alf P. Steinbach wrote:
>>
>>> On 1/15/2018 7:55 PM, Ian Collins wrote:
>>>
>>>> On 01/16/2018 03:34 AM, Alf P. Steinbach wrote:
>>>>
>>>>> Here's another example:
>>>>>
>>>>> void update_menus()
>>>>> {
>>>>> using Static_id = menu::Static_cmd_id;
>>>>> const auto set_item_check = [&]( const Static_id::Enum i,
>>>>> const bool value )
>>>>
>>>> Why did you const qualify the parameters?
>>>
>>> The rationale for `const` on formal arguments in a function definition
>>> is the same as the rationale for `const` on local variables, and vice versa.
>>>
>>> Mainly that it, in the general case, constrains the possible effects of
>>> the code, so that the code is easier to grok and reason about.
>>
>> Um, you are probably in a small minority there. To my eyes they are
>> just clutter. In our code base I remove spurious parameter qualifiers
>> almost as zealously as I remove passing integral types by const reference!
>
> Oddly, I'm with Alf here. Maybe not for tiny function bodies like this one,
> but not just for huge ones either.

How large the function is makes a big difference. I use const
where I think it adds something, and not where it doesn't. In
small functions it rarely does, and most function bodies are
small (or they should be). Of course long functions are another
matter, but in those cases I would rather see effort be applied
to dividing the function appropriately than to making the long
function easier to live with.

> To me, /not/ marking them 'const' signals an intent to modify them
> later on in the code.

For me 'const' signifies something worth bringing to the attention
of the reader. Overusing const is just as much of a negative as
underusing it.

Tim Rentsch

unread,
Jan 24, 2018, 4:35:01 PM1/24/18
to
Jorgen Grahn <grahn...@snipabacken.se> writes:

> On Fri, 2018-01-12, arnuld wrote:
>
>> #include <iostream>
>>
>> bool askSample();
>
> I'd place the implementation of askSample() here, in an anonymous
> namespace. People probably think differently about it, but I really
> dislike forward declarations; I'm much happier with having functions
> (and other things) appear just when they're needed -- even though that
> means main() as to come last.

I dislike having to write forward declarations, and to a lesser
extent having to see them while reading. But I dislike those
things a lot less than having to read code backwards.

Alf P. Steinbach

unread,
Jan 24, 2018, 4:48:26 PM1/24/18
to
I'm not sure I grok what you mean here. Surely you don't read the code
sequentially?


Cheers!,

- Alf


Vir Campestris

unread,
Jan 24, 2018, 4:55:28 PM1/24/18
to
On 24/01/2018 21:24, Tim Rentsch wrote:
> For me 'const' signifies something worth bringing to the attention
> of the reader. Overusing const is just as much of a negative as
> underusing it.

If I was designing a language from scratch I think I'd make const default.

The fact that we have to specify const, but not writeable, is IMHO a
historical accident.

Andy

Richard

unread,
Jan 24, 2018, 5:07:17 PM1/24/18
to
[Please do not mail me a copy of your followup]

Tim Rentsch <t...@alumni.caltech.edu> spake the secret code
<kfnk1w7...@x-alumni2.alumni.caltech.edu> thusly:

>I dislike having to write forward declarations, and to a lesser
>extent having to see them while reading. But I dislike those
>things a lot less than having to read code backwards.

"Backwards" is ambiguous because it means top-to-bottom for someone
who likes to read code in a bottom-up manner and it means
bottom-to-top for someone who likes to read code in a top-down manner.

IMO, it is a useful skill to read code in either direction, but
naturally one can still have a preference.

Daniel

unread,
Jan 24, 2018, 6:07:18 PM1/24/18
to
On Wednesday, January 24, 2018 at 4:55:28 PM UTC-5, Vir Campestris wrote:
>
> If I was designing a language from scratch I think I'd make const default.
>
I'd be skeptical if any new language would take const from C++. const can be thought of as an ad hoc construct that effectively provides a class with a second interface. Modern languages that have interfaces don't need that, you would just provide an interface with an immutable specification, if that was what you wanted.

Daniel

Jorgen Grahn

unread,
Jan 25, 2018, 1:49:15 AM1/25/18
to
On Wed, 2018-01-24, Tim Rentsch wrote:
> Jorgen Grahn <grahn...@snipabacken.se> writes:
...
[const on parameters and locals]

>> Oddly, I'm with Alf here. Maybe not for tiny function bodies like this one,
>> but not just for huge ones either.
>
> How large the function is makes a big difference. I use const
> where I think it adds something, and not where it doesn't. In
> small functions it rarely does, and most function bodies are
> small (or they should be). Of course long functions are another
> matter, but in those cases I would rather see effort be applied
> to dividing the function appropriately than to making the long
> function easier to live with.

Yes, but refactoring a function is more work and more risk.

One of my favorite ways of deciphering someone else's overlong
function is to add const, so I can be sure 'foo' set near the
beginning of the function has the same value one screenful later.
Then when I understand it better, it's easier to refactor.

>> To me, /not/ marking them 'const' signals an intent to modify them
>> later on in the code.
>
> For me 'const' signifies something worth bringing to the attention
> of the reader. Overusing const is just as much of a negative as
> underusing it.

Different mindsets, then.

Jorgen Grahn

unread,
Jan 25, 2018, 2:02:48 AM1/25/18
to
I see what he means, I think: he wants to open a file and see the most
important stuff at the top -- constructors and public functions, if
it's a class; or main() if it's the main source.

That's what I'd like to see too, ideally ... but if I tried to do it
that way I'm afraid I wouldn't split out helper functions as often as
I should. I can't be bothered to maintain three things: the
declaration of helper(), the call to helper(), and the implementation
of helper(), somewhere far down in the file.

Ian Collins

unread,
Jan 25, 2018, 2:16:40 AM1/25/18
to
I agree, helpers should be in the anonymous namespace, which has the
side effect of grouping then tidily.

--
Ian.

Daniel

unread,
Jan 25, 2018, 8:30:57 AM1/25/18
to
On Wednesday, January 24, 2018 at 6:07:18 PM UTC-5, Daniel wrote:
> On Wednesday, January 24, 2018 at 4:55:28 PM UTC-5, Vir Campestris wrote:
> >
> > If I was designing a language from scratch I think I'd make const default.
> >
> I'd be skeptical ...

Ahh, I should have checked the context before replying, thought it
was about function signatures, as it is, my comment makes no sense.

Daniel

Manfred

unread,
Jan 25, 2018, 11:01:28 AM1/25/18
to
On 1/25/2018 7:48 AM, Jorgen Grahn wrote:
> On Wed, 2018-01-24, Tim Rentsch wrote:
>> Jorgen Grahn <grahn...@snipabacken.se> writes:
> ...
> [const on parameters and locals]
>
>>> Oddly, I'm with Alf here. Maybe not for tiny function bodies like this one,
>>> but not just for huge ones either.
Me too, in fact I have an habit of const-qualifying most locals per
default. Less than most for parameters, but still not that infrequently.

I may add that complexity of a code fragment is directly proportional to
the amount of data variables involved (which in fact constitute the
state of the machine 'fragment'), so constraining such data as const
helps managing its complexity.

>>
>> How large the function is makes a big difference. I use const
>> where I think it adds something, and not where it doesn't. In
>> small functions it rarely does, and most function bodies are
>> small (or they should be). Of course long functions are another
>> matter, but in those cases I would rather see effort be applied
>> to dividing the function appropriately than to making the long
>> function easier to live with.

I would say it is about function complexity more than size.

>
> Yes, but refactoring a function is more work and more risk.
>
> One of my favorite ways of deciphering someone else's overlong
> function is to add const, so I can be sure 'foo' set near the
> beginning of the function has the same value one screenful later.
> Then when I understand it better, it's easier to refactor.
>
>>> To me, /not/ marking them 'const' signals an intent to modify them
>>> later on in the code.
>>
>> For me 'const' signifies something worth bringing to the attention
>> of the reader. Overusing const is just as much of a negative as
>> underusing it.
>
> Different mindsets, then.
>
Different mindsets indeed.

Jorgen Grahn

unread,
Jan 26, 2018, 10:03:14 AM1/26/18
to
I should probably explain here that I reopen that namespace; there
might be several of these in a given source file of mine:

namespace {
void some_helper(...) { ... }
}

But yes, they'd be grouped in a listing of names.

Tim Rentsch

unread,
Jan 31, 2018, 2:33:05 AM1/31/18
to
Jorgen Grahn <grahn...@snipabacken.se> writes:

> On Wed, 2018-01-24, Tim Rentsch wrote:
>
>> Jorgen Grahn <grahn...@snipabacken.se> writes:
>
> ...
> [const on parameters and locals]
>
>>> Oddly, I'm with Alf here. Maybe not for tiny function bodies like this one,
>>> but not just for huge ones either.
>>
>> How large the function is makes a big difference. I use const
>> where I think it adds something, and not where it doesn't. In
>> small functions it rarely does, and most function bodies are
>> small (or they should be). Of course long functions are another
>> matter, but in those cases I would rather see effort be applied
>> to dividing the function appropriately than to making the long
>> function easier to live with.
>
> Yes, but refactoring a function is more work and more risk.

I am taking this to mean you are talking about decomposing a
function in two or more smaller ones, rather than shortening or
simplifing a function body "in place". (To be fair my word
"dividing" was overspecific - I could have used a more neutral
word like "revising". But no matter.)

In any case, yes, decomposing a function into several is more
work, but the payoff is a lot higher. Probably the ROI is higher
for decomposing than it is for adding 'const' in several places.
Adding const does have the advantage of being more incremental.
The benefit just doesn't go as far, that's all I'm saying.

I'm not convinced that de-/re-composing a function carries more
risk necessarily. That depends on how much effort it put in to
the revising, and what testing methodology is being used. I
suppose in some absolute sense the risk is smaller, since adding
a 'const' somewhere is very unlikely to cause a problem (assuming
the code still compiles, of course). But the risk/payoff ratio
may very well be higher. The question is more complicated in
C++, where IIANM the presence of 'const' can change things in
unobvious ways due to things like function overloading. It
probably won't, but it might.

> One of my favorite ways of deciphering someone else's overlong
> function is to add const, so I can be sure 'foo' set near the
> beginning of the function has the same value one screenful later.
> Then when I understand it better, it's easier to refactor.

As it turns out I have been doing a fair amount of refactoring
work recently. It's almost always good to start small, looking
for ways to get some local improvements, before moving up to
the scale of decomposing big functions. Adding 'const' can be
one way to help with that, depending on what the starting point
is.

>>> To me, /not/ marking them 'const' signals an intent to modify them
>>> later on in the code.
>>
>> For me 'const' signifies something worth bringing to the attention
>> of the reader. Overusing const is just as much of a negative as
>> underusing it.
>
> Different mindsets, then.

I think the word "mindsets" is not really apropos here. What I
think you're talking about is what 'const' conveys to you, or
what it does or should convey to others. (Or similarly its
absence, I don't mean to distinguish those two cases.) What I am
talking about is (empirically) how I use 'const', not about what
it conveys or is meant to convey. As a rule I try not to assume
when reading other people's code that they think the same way I
do, and conversely.

Tim Rentsch

unread,
Jan 31, 2018, 2:37:59 AM1/31/18
to
Manfred <non...@invalid.add> writes:

> On 1/25/2018 7:48 AM, Jorgen Grahn wrote:
>
>> On Wed, 2018-01-24, Tim Rentsch wrote:
>>
>>> Jorgen Grahn <grahn...@snipabacken.se> writes:
>>
>> ...
>> [const on parameters and locals]
>>
>>>> Oddly, I'm with Alf here. Maybe not for tiny function bodies like this one,
>>>> but not just for huge ones either.
>
> Me too, in fact I have an habit of const-qualifying most locals per
> default. Less than most for parameters, but still not that
> infrequently.
>
> I may add that complexity of a code fragment is directly proportional
> to the amount of data variables involved (which in fact constitute the
> state of the machine 'fragment'), so constraining such data as const
> helps managing its complexity.
>
>>> How large the function is makes a big difference. I use const
>>> where I think it adds something, and not where it doesn't. In
>>> small functions it rarely does, and most function bodies are
>>> small (or they should be). Of course long functions are another
>>> matter, but in those cases I would rather see effort be applied
>>> to dividing the function appropriately than to making the long
>>> function easier to live with.
>
> I would say it is about function complexity more than size.

I didn't mean "large" to be just about length. Length is one
aspect, but certainly not the only aspect.

Tim Rentsch

unread,
Jan 31, 2018, 3:51:53 AM1/31/18
to
Have you ever noticed how newspaper articles are written? They
start with a single concise paragraph that briefly states the
most essential details, at a high level. As the article goes on,
more and more detail is added, in a more or less breadth-first
order, so that the picture is gradually filled in everywhere,
without focusing on small details in any one area too early. The
result is you can stop reading kind of at any point, depending on
how much detail you want - sort of like how the graphic technique
of progressive refinement works.

Conversely, have you ever looked at the "live blogs" written by,
eg, sports writers covering sports events in real time? The
distinguishing feature of the articles I'm talking about is that
they are in reverse chronological order - as new bits and pieces
are added, they are added at the top rather than the bottom.
Thus if you want to read about the game from the beginning you
need to start near the bottom, read a paragraph or two while
scrolling towards the bottom of the page, then scroll the other
way to get to the next entry - back and forth in kind of a
zig-zag pattern. It's quite...hmmm...unsatisfying.

I find it very helpful when code is laid out in a mostly temporal
order, with calling functions written before called functions,
and child functions called earlier by a parent written before
child functions called later by the same parent. Of course there
are more elaborate connection structures possible, but to the
extent the call graph is a tree this corresponds to a prefix
traversal of the tree.

How I read code is probably too complicated to describe (if
indeed I even know all the various detours that I take). But for
sure I don't read code sequentially line-by-line. For one thing
my unit of reading is mostly one function body at a time. What
may be more important is that I don't necessarily read everything
but will skip some pieces here and there. When code is laid out
in a mostly temporal order, there is a very good chance that what
I want to read next is just further down the page. The general
direction of page-turning (or scrolling, if you will) is largely
the same - starting at the top, headed generally towards the
bottom, skipping pages now and then when there are details not
important at the moment, plus the occasional sideways jog when I
need to look back at something that happened earlier, or to skip
ahead briefly to look at a detail in a shared leaf node (and so
likely to be out of temporal order).

I believe there are other reasons that code laid out in a mostly
temporal order is easier to read and comprehend. In any case
what I was talking about is a caller-before-callee ordering for
the functions of a program or program sub-component.

Tim Rentsch

unread,
Jan 31, 2018, 4:03:51 AM1/31/18
to
What's sad is that C++ compilers have the machinery they needs,
or at least most of it, so that forward function declarations are
not necessary. If you will excuse a rather dumb example:

#include <stdio.h>

unsigned a, b, c;

struct Program {

int
main( int argc, char **argv ){
foo();
bas();
bar();
printf( "a, b, c: %u %u %u\n", a, b, c );
return 0;
}

void
foo(){
a = 4;
}

void
bas(){
b = 49;
for( unsigned i = 0; i < a; i++ ) b += i*i;
}

void
bar(){
c = 121;
for( unsigned i = 0; i < b; i++ ) c -= i;
}

} program;

int
main( int argc, char **argv ){
return program.main( argc, argv );
}

It would be nice to push the function-calling capability for
methods inside a struct/class up to the level of outer functions
in each entire translation unit.
0 new messages