Wednesday, April 17, 2019

Digest for comp.lang.c++@googlegroups.com - 25 updates in 3 topics

Ben Bacarisse <ben.usenet@bsb.me.uk>: Apr 17 01:06AM +0100

> {
> // The logical "else" part.
> }
 
That looks like the Python meaning, not the one RCH was suggesting. I
think RCH's intent can be written as:
 
bool loop_body_executed = false;
for (INIT; COND; UPDATE, loop_body_executed = true) {
// ...
}
if (!loop_body_executed) {
// The logical "else" part.
}
 
--
Ben.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 17 04:45AM +0200

On 17.04.2019 02:06, Ben Bacarisse wrote:
> if (!loop_body_executed) {
> // The logical "else" part.
> }
 
Thanks. That seems to indicate that there are at least two about equally
convincing but exactly opposite notions of what `else` should mean if it
were introduced as an extension to `for`...
 
---
 
Anyway I find your example interesting because it's easier to read, and
therefore grok, than my example that, more ideally, constrains the scope
for modification of the variable.
 
And I think that's due to two reasons:
 
• That your example is shorter, mainly because of formatting.
• That C++, from its C heritage, supports the changing-variables style
of coding, and does not so much support expression based coding.
 
In some other contexts the shorter formatting tends to produce what in
my eyes is a gray wall of compact code, so I'm wary of adopting it. It's
nice for books and articles, though, where vertical space is a limited
resource. But on the third and gripping hand I may be too old to change
formatting preferences again...
 
---
 
Going back even further historically, C's parent language BCPL had a
construct that one can think of as "arithmetic blocks", like a curly
braces compound statement that could return a value.
 
And expressing your example with an imaginary such construct it's not
significantly more to read, and then properly constrains the scope where
the code can change or influence the value of the boolean:
 
const bool loop_body_executed = BCPL_BLOCK {
for (INIT; COND; UPDATE) {
if( SOMETHING ) { return true; }
}
return false;
};
if( not loop_body_executed ) {
// The logical "else" part.
}
 
 
---
 
As it happens it's easy to define a macro like BCPL_BLOCK:
 
#define BCPL_BLOCK ~[&]()
 
... where the `~` operator is defined as e.g.
 
namespace lambda_support
{
using std::declval;
 
template< class Func
, class Enabled_ = decltype( declval<Func>()() )
 
inline auto operator~( Func const& f )
-> decltype(( f() ))
{ return f(); }
} // namespace lambda_support
 
One just needs a `using` statement for it. Hence the need for SFINAE to
ensure that this definition only kicks in, that it's only found, when
`~` is applied to something callable without arguments. It should
probably be even more constrained than what I managed above.
 
So, that notation is not hypothetical. It's also easy to provide
bindings for the lambda, e.g. using the `%` operator. It would be (or
was when I tried it out, some years ago, then named `$invoked_with`
instead of BCPL_BLOCK) a rather ugly hack that didn't entirely prevent
incorrect use, but if one could get language and/or standard library
support then it could be safe, because the standard library is allowed
to use magic. I'd prefer a core language prefix invocation operator.
 
 
Cheers!,
 
- Alf
David Brown <david.brown@hesbynett.no>: Apr 17 09:32AM +0200

On 17/04/2019 04:45, Alf P. Steinbach wrote:
 
> Thanks. That seems to indicate that there are at least two about equally
> convincing but exactly opposite notions of what `else` should mean if it
> were introduced as an extension to `for`...
 
And that would indicate that neither is a good idea, and "for else"
should be avoided. Both cases can be easily and clearly handled by a
bool flag, which a good compiler can often eliminate entirely (and it's
a cheap solution even if the compiler can't remove it).
 
 
> • That your example is shorter, mainly because of formatting.
> • That C++, from its C heritage, supports the changing-variables style
> of coding, and does not so much support expression based coding.
 
I think the principle of avoiding changing variables is good, but it can
be taken too far. Many factors contribute to code clarity - obsessing
over any one of them is likely to give you worse (i.e., less legible)
code in the end.
 
> ensure that this definition only kicks in, that it's only found, when
> `~` is applied to something callable without arguments. It should
> probably be even more constrained than what I managed above.
 
You do like to come up with some convoluted code, don't you? I found
that one interesting, however. Your next challenge is to use concepts
to remove the "Enabled" bit.
 
 
Bart <bc@freeuk.com>: Apr 17 11:38AM +0100

On 17/04/2019 08:32, David Brown wrote:
 
>> Thanks. That seems to indicate that there are at least two about equally
>> convincing but exactly opposite notions of what `else` should mean if it
>> were introduced as an extension to `for`...
 
Its use in Python is not hard to understand.
 
Its use as described in the OP is harder (RCH's ideas for features
always are).
 
> should be avoided. Both cases can be easily and clearly handled by a
> bool flag, which a good compiler can often eliminate entirely (and it's
> a cheap solution even if the compiler can't remove it).
 
The idea is to avoid the extra logic. Here's a typical use in one of my
languages (real example):
 
for sw to optionnames.len do
if eqstring(name,optionnames[sw]) then
do_option(sw,value)
exit
fi
else
println "Unknown option:",name
stop 1
od
 
This for a language at the level of C (I'm posting from that group). A
higher level might just say 'sw in optionnames', but since many won't
have eliminated for-loops completely, there is likely still to be a use
for for-else.
 
The alternative as you say is to use a flag:
 
optionno:=0
for sw ...
...
optionno:=sw
...
od
if optionno then
do_option ...
else
println ...
fi
 
I must have written a thousand such loops; the for-else feature provides
a welcome respite, as well as a self-contained solution in one statement.
 
The flag version introduces a new variable that demands an extra, wider
scope, something at odds with your preference for narrower block scopes.
David Brown <david.brown@hesbynett.no>: Apr 17 02:05PM +0200

On 17/04/2019 12:38, Bart wrote:
>>> convincing but exactly opposite notions of what `else` should mean if it
>>> were introduced as an extension to `for`...
 
> Its use in Python is not hard to understand.
 
That is debatable. But I agree it is easier (and more useful) than
Rick's suggestion.
 
>         println "Unknown option:",name
>         stop 1
>     od
 
bool found = false;
int sw;
for (sw = 0; sw < len; sw++) {
if (strcmp(name, options[sw]) == 0) {
found = true;
break;
}
}
if (found) {
do_option(sw, value);
} else {
printf("Unknown option: %s\r\n", name);
stop(1);
}
 
The "for else" construct is not necessary, and the bool flag solution
will be just as efficient. Structuring the code as "try to find the
match, then handle the result" is arguably neater (and by "arguably", I
don't mean it is /definitely/ neater). It also makes it easier to
refactor the code if you have a different way of searching, perhaps as a
separate function.
 
 
>     fi
 
> I must have written a thousand such loops; the for-else feature provides
> a welcome respite, as well as a self-contained solution in one statement.
 
A smaller and more compact solution could be nice - but that would, as
you say, require a higher level language.
 
 
> The flag version introduces a new variable that demands an extra, wider
> scope, something at odds with your preference for narrower block scopes.
 
I have a preference for narrower scopes, all else being equal. But if
the data is needed over a wider range, then a wider scope is the answer.
Bart <bc@freeuk.com>: Apr 17 01:57PM +0100

On 17/04/2019 13:05, David Brown wrote:
>>>> were introduced as an extension to `for`...
 
>> Its use in Python is not hard to understand.
 
> That is debatable.
 
The controversy is with the use of the 'else' keyword. The idea of
having code executed only on normal loop termination, not so much.
 
> }
 
> The "for else" construct is not necessary, and the bool flag solution
> will be just as efficient.
 
So why not:
 
if (found) {
do_option(sw, value);
}
if (!found) {
printf("Unknown option: %s\r\n", name);
exit(1);
}
 
We don't really need 'if else' either. (I'm sure I didn't have that in
Fortran years ago.)
 
 
> A smaller and more compact solution could be nice - but that would, as
> you say, require a higher level language.
 
By higher level I mean something like:
 
do_option(name in optionnames, value)
 
'in' would return 1..len or 0, so do_option would have to deal with a
option code of 0, to keep it simple.
 
Higher level code tends not to have so many explicit loops, but so long
as for-loops /are/ still used, then an 'else' clause containing
dedicated code for a normal termination rather than a break will still
be useful.
David Brown <david.brown@hesbynett.no>: Apr 17 03:36PM +0200

On 17/04/2019 14:57, Bart wrote:
 
>> That is debatable.
 
> The controversy is with the use of the 'else' keyword. The idea of
> having code executed only on normal loop termination, not so much.
 
It is the use of the "else" keyword that you said was not hard to
understand in Python, and I said it was debatable how hard that is. The
poster that first mentioned said that the "else" keyboard in Python
"for" loops is more often a subject of confusion than a useful coding
technique.
 
Clearly I don't disagree that sometimes it is useful to execute
different code when a loop is terminated early.
 
>      }
 
> We don't really need 'if else' either. (I'm sure I didn't have that in
> Fortran years ago.)
 
Sometimes that is a preferable arrangement. But this is a straw man
(whataboutism, if you prefer) - we have "if ... else ..." in C. A key
difference is that "if ... else ..." is extremely useful, and extremely
common in most imperative languages. A "for ... else ..." construct is
only occasionally useful - as for all constructs, that usefulness must
be weighed against the additional learning and the potential for
confusion. For "if ... else ...", the balance is clearly on the
"useful" side. For "for ... else ...", the balance would appear to be
on the "confusing" side.
 
(Before you bring in more whataboutisms, C already has constructs that
are more often confusing than useful. There is no need to mention them
or list them.)
 
 
>     do_option(name in optionnames, value)
 
> 'in' would return 1..len or 0, so do_option would have to deal with a
> option code of 0, to keep it simple.
 
That is an odd construct - I would not expect to see it, or immediately
know what was meant. I would rather expect something like:
 
if (name in optionnames) {
do_option(optionnames[name], value);
} else {
print "Unknown option"
}
 
or
 
try {
do_option(optionnames[name], value);
} except on key_error {
print "Unknown option"
}
 
(I am making up high-level syntax as I go here.)
 

 
> as for-loops /are/ still used, then an 'else' clause containing
> dedicated code for a normal termination rather than a break will still
> be useful.
 
I don't disagree that a "for ... else ..." clause could be useful. But
I am not convinced that it is useful enough to overcome potential
confusion - I think its use would be rare, and alternative simple and
clear solutions are easily available.
Bart <bc@freeuk.com>: Apr 17 03:05PM +0100

On 17/04/2019 13:05, David Brown wrote:
> }
> if (found) {
> do_option(sw, value);
 
Another point is that as written, 'sw' has to be known outside so cannot
be local to the loop. (In my example, the code to be executed can be
brought inside the loop body; sometimes it can't. But 'found' needs to
be outside.)
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 17 04:15PM +0200

On 17.04.2019 14:57, Bart wrote:
 
>     do_option(name in optionnames, value)
 
> 'in' would return 1..len or 0, so do_option would have to deal with a
> option code of 0, to keep it simple.
 
That places responsibility for dealing with an unknown option down in
`do_option`, via an `if` or `switch` or something.
 
I'd rather have that logic up front:
 
if( const int id = 1 + my::index_of( name, optionnames ) ) {
app::do_option( id, value );
} else {
my::fail( ""s + __func__ + " - unknown option '" + name + "'" );
}
 
> as for-loops /are/ still used, then an 'else' clause containing
> dedicated code for a normal termination rather than a break will still
> be useful.
 
Consider also
 
[](){
for( const& string item: optionnames ) {
if( item == name ) {
app::do_option( 1 + &item - &optionnames[0], value );
return;
}
}
my::fail( ""s + __func__ + " - unknown option '" + name + "'" );
}();
 
`return` is a nice statement; here it returns to the point after the
last semicolon.
 
The perhaps currently cryptic JavaScript-like start and end of that code
is a pattern that one might as well get used to.
 
 
Cheers!,
 
- Alf
Bart <bc@freeuk.com>: Apr 17 03:16PM +0100

On 17/04/2019 14:36, David Brown wrote:
>> option code of 0, to keep it simple.
 
> That is an odd construct - I would not expect to see it, or immediately
> know what was meant.
 
Python has "in" but just returns True or False, which is not very
helpful. My version returns the index where a occurs in b, although most
useful for 1-based lists.
 
I would rather expect something like:
 
> if (name in optionnames) {
> do_option(optionnames[name], value);
 
You're doing a double lookup, one with "in", and one with [], which
latter would require optionnames to be a dict. It gets messy.
 
 
> I am not convinced that it is useful enough to overcome potential
> confusion - I think its use would be rare, and alternative simple and
> clear solutions are easily available.
 
It's rare partly because languages don't have it!
 
Although I already said it would have problems being added to C because
of the ambiguity of 'else'.
Juha Nieminen <nospam@thanks.invalid>: Apr 17 07:06AM

As an avid armchair psychologist, it has always fascinated me why some
people just hate namespace prefixes in C++, and go to great lengths
to avoid them and will rabidly defend this practice, and oppose their
use. No amoung of argumentation will convince them otherwise.
 
I have literally never, ever, during my entire life (being programming
as a hobby and as my payjob for over 20 years), seen somebody complain
about having to write prefixes when they use some library (eg. some
C library) that has a common prefix in all of its names. Not even
if that prefix is separated from the rest of the name with an
underscore. They don't mind having to write "prefix_name()", but for
some peculiar reason they hate having to write "prefix::name()", and will
get rid of having to do it.
 
What's the difference?
 
I don't think the explanation is in the characters themselves. I don't
think '::' is somehow special compared to '_' that would elicit such
a contrarian reaction. So what is it?
 
I believe that it has to do with the fact that writing the prefix
is *optional* in the case of C++ namespaces. Somehow the notion that
it's optional makes them hate writing it. Whan it's *not* optional,
as in it being part of the name itself (like is the case with many
C libraries), it doesn't trigger the aversion reaction. However, just
the knowledge that it's optional makes them hate having to write it.
 
I bet that if they didn't know that writing namespace prefixes is
optional, that you can bypass it with a `using` expression, they
would not protest having to write it.
leigh.v.johnston@googlemail.com: Apr 17 12:36AM -0700

On Wednesday, April 17, 2019 at 8:06:59 AM UTC+1, Juha Nieminen wrote:
 
> I bet that if they didn't know that writing namespace prefixes is
> optional, that you can bypass it with a `using` expression, they
> would not protest having to write it.
 
The answer to your question is irrationality. Alf is irrational. The cause could be a mild mental disorder.
 
/Leigh
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 17 10:14AM +0200

>> would not protest having to write it.
 
> The answer to your question is irrationality. Alf is irrational. The
> cause could be a mild mental disorder.
I gather that that's an effort to connect me to Juha's remarks, and as
such it's dishonest.
 
I and I guess others value many of your contributions to the group, but
postings like those about sausages, the rabid religious discussions, the
equally rabid swearing, the apparently seriousness of making a universal
compiler, and occasional technical or ad hominem trolling such as now,
detracts from that.
 
 
Cheers!,
 
- Alf
leigh.v.johnston@googlemail.com: Apr 17 02:26AM -0700

On Wednesday, April 17, 2019 at 9:14:26 AM UTC+1, Alf P. Steinbach wrote:
> equally rabid swearing, the apparently seriousness of making a universal
> compiler, and occasional technical or ad hominem trolling such as now,
> detracts from that.
 
And when you add all those things (including the posts about sausages) together the result is still less egregious than your C++ coding style, Alf.
 
/Leigh
"Fred.Zwarts" <F.Zwarts@KVI.nl>: Apr 17 11:59AM +0200

"Juha Nieminen" schreef in bericht
news:q96ja6$2l60$1@adenine.netfront.net...
 
>I bet that if they didn't know that writing namespace prefixes is
>optional, that you can bypass it with a `using` expression, they
>would not protest having to write it.
 
I won't say that I hate prefixes, sometimes I use them. But I prefer to use
'using', because it makes it easier for me to document where the names come
from.
I group the 'using' expressions in the same order as the #include lines. The
block of #include lines is followed by a few blocks of 'using' declarations.
One block for each #include.
In this way it is easy to see why a particlular #include is needed and also
from which #include the std::name originates.
 
E.g.:
 
#include <functional>
#include <exception>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>
 
 
// Import some symbols from the include files.
 
using std::ref;
using std::reference_wrapper;
 
using std::exception;
 
using std::runtime_error;
 
using std::string;
 
using std::type_info;
 
using std::vector;
 
This shows immediately why <functional> is included.
Another reason, in particular for names that are used very often, is that in
complex expressions 'string' is easier to read than 'std::string', because
it is easier to keep the expressions short.
leigh.v.johnston@googlemail.com: Apr 17 03:08AM -0700

On Wednesday, April 17, 2019 at 10:59:27 AM UTC+1, F.Zwarts wrote:
> Another reason, in particular for names that are used very often, is that in
> complex expressions 'string' is easier to read than 'std::string', because
> it is easier to keep the expressions short.
 
This is a fallacious argument. "std::" is ONLY FIVE EXTRA CHARACTERS. Not using the prefix actually makes things harder not easier to grok as you can't tell at a glance what code is standard and what code is non-standard.
 
/Leigh
Ian Collins <ian-news@hotmail.com>: Apr 17 10:17PM +1200

On 17/04/2019 19:06, Juha Nieminen wrote:
 
> I bet that if they didn't know that writing namespace prefixes is
> optional, that you can bypass it with a `using` expression, they
> would not protest having to write it.
 
It depends...
 
Writing std:: isn't particularly burdensome, but if the namespace or
namespaces are long (such as those produced when using Google protpbuf),
a using aids readability.
 
--
Ian.
"Fred.Zwarts" <F.Zwarts@KVI.nl>: Apr 17 12:41PM +0200

schreef in bericht
news:a24842c2-63de-4ff9-8ad8-0766d1db0f87@googlegroups.com...
>using the prefix actually makes things harder not easier to grok as you
>can't tell at a glance what code is standard and what code is non-standard.
 
>/Leigh
 
If somebody missed the fact that string is defined in the std:: namespace,
than he is probably a very inexperienced C++ programmer. For most C++
programmers, std:: adds nothing as a prefix to string in terms of
readability.
leigh.v.johnston@googlemail.com: Apr 17 03:54AM -0700

On Wednesday, April 17, 2019 at 11:41:58 AM UTC+1, F.Zwarts wrote:
> than he is probably a very inexperienced C++ programmer. For most C++
> programmers, std:: adds nothing as a prefix to string in terms of
> readability.
 
Nonsense. These days with the idiom of using `auto` almost everywhere readability shouldn't be an issue and for the few places where we can't use `auto` it is more important than ever to fully qualify.
 
/Leigh
Bart <bc@freeuk.com>: Apr 17 12:02PM +0100

>> complex expressions 'string' is easier to read than 'std::string', because
>> it is easier to keep the expressions short.
 
> This is a fallacious argument. "std::" is ONLY FIVE EXTRA CHARACTERS. Not using the prefix actually makes things harder not easier to grok as you can't tell at a glance what code is standard and what code is non-standard.
 
"std::" is nearly the same length as "string". So half of what you're
trying to see is noise. And while "string" and "vector" are obviously
distinct, "std::string" and "std::vector" are 45% identical by
character, and 66% identical by token.
 
Imagine if every noun in a piece of writing was prefixed with "eng::" to
tell you it was standard English. It would be a joke.
 
C++ has enough problems with readability without deliberately making it
worse.
leigh.v.johnston@googlemail.com: Apr 17 04:13AM -0700

On Wednesday, April 17, 2019 at 12:03:07 PM UTC+1, Bart wrote:
> tell you it was standard English. It would be a joke.
 
> C++ has enough problems with readability without deliberately making it
> worse.
 
In your opinion it is made worse; in my opinion and the opinion of others it is made worse by NOT having the prefix.
 
/Leigh
Paavo Helde <myfirstname@osa.pri.ee>: Apr 17 02:19PM +0300

On 17.04.2019 10:06, Juha Nieminen wrote:
> people just hate namespace prefixes in C++, and go to great lengths
> to avoid them and will rabidly defend this practice, and oppose their
> use. No amoung of argumentation will convince them otherwise.
 
The namespaces are specifically designed in the way that they can be
omitted if so desired. This is a feature, not a bug. If people are using
a feature, there is nothing more to say, the feature is there to be used.
 
Of course, as any other feature this one can be overused or misused as
well. Obviously, omitting namespaces would be bad if it makes the code
harder to read, instead of making it easier.
 
Alas, the trouble is that what is harder and what is easier heavily
depends on the person reading the code and what he/she is accustomed to.
Somebody with a lot of experience and good memory might immediately
recognize which namespace the names like 'inclusive_scan' or
'greg_month' come from and what they mean, whereas for others this may
be a challenge.
 
I guess it's the same as with the tab/space issue. Whatever you do you
will never find a variant which would satisfy all people.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 17 11:36AM

On Wed, 2019-04-17, Juha Nieminen wrote:
> people just hate namespace prefixes in C++, and go to great lengths
> to avoid them and will rabidly defend this practice, and oppose their
> use. No amoung of argumentation will convince them otherwise.
 
I think c.l.c++ posters are atypical C++ users these days. In real
life I've never met anyone who avoids prefixes that way. So in that
sense it's a non-issue ... I try not to worry about it.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 17 01:15PM

On Wed, 2019-04-17, Fred.Zwarts wrote:
>>can't tell at a glance what code is standard and what code is non-standard.
 
>>/Leigh
 
> If somebody missed the fact that string is defined in the std:: namespace,
 
It's not, not necessarily. I may want to use the name "string"
locally, and don't expect such a name to conflict with the standard
library. Not to mention names like find().
 
> than he is probably a very inexperienced C++ programmer. For most C++
> programmers, std:: adds nothing as a prefix to string in terms of
> readability.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
"Öö Tiib" <ootiib@hot.ee>: Apr 17 04:49AM -0700

> surprising to users if they both produced the same string after
> formatting. It may not be a big deal for many users, but why
> introduce unnecessary differences for no good reason?
 
Reasoning depends on who are your customers. Some bigger
players in that "standardization" game see benefits in
unreasonable incompatibilities between implementations.
Rest of participants don't want things to be as close to
whatever is "implementation defined" as possible; they
usually want things to be platform agnostic if possible.
 
> fairly simple for the various forms of infinity, there's a bit more
> complexity with NaNs. I'm less clear on what I want to do for
> conversions from *text* format.
 
It would be fine for me if >> did parse "infinity" as well (and then
both "inf" and "infinity" on all platforms) but I would dislike
if << would output "infinity" on some platforms and "inf" on
others. If that can be turned off with some compile time switch
then I would be happy with it.
 
> happen if there are actual NaNs. I don't think it's unreasonable to
> support formatting NaN payloads if the implementation does so for
> normal floats.
 
The goals and preferences of target audiences can be
diametrically opposed there, but my impression is that
majority likes portability.
I have had experience that the programs that use NaNs as valid
and meaningful values (in meanings of "not measured",
"unknown" and/or "marked as noise") can have majority of data
as NaNs.
 
> This may ultimately need some configuration options, but I'd like to
> be able to provide good defaults for most cases.
 
If such NaN payload support can be turnable off compile time then
I would be happy with it.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: