Wednesday, June 27, 2018

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

Sam <sam@email-scan.com>: Jun 27 05:14PM -0400

Stefan Ram writes:
 
> auto f();
 
> is hardly helpful. So should we avoid the auto return type
> for functions which are part of an API for this reason?
 
Avoiding a very useful, new language feature only because a documentation
tool can't deal with it doesn't seem like a good reason to me.
 
With the increased complexity of C++, only an actual C++ compiler can fully
understand C++ code. This is not the only part of modern C++ that doxygen
doesn't quite pick up.
 
I find doxygen very useful, and I use it a lot. I do not take into
consideration doxygen's limitations when writing code. I only review
doxygen's output after the fact; and make whatever manual fixes and tweaks
to doxygen's output that can be reasonably done.
Paavo Helde <myfirstname@osa.pri.ee>: Jun 28 12:34AM +0300

On 27.06.2018 23:29, Stefan Ram wrote:
> auto f();
 
> is hardly helpful. So should we avoid the auto return type
> for functions which are part of an API for this reason?
 
Nope, the tools should be updated to cope with the new language rules.
 
However, auto return type should be avoided in API-s because an API
ought to define an interface (that's the I) but auto depends on the
implementation details. With something having an official API it should
be vice versa, implementation should depend on the interface.
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jun 27 02:37PM -0700

On 6/27/2018 2:34 PM, Paavo Helde wrote:
>>    for functions which are part of an API for this reason?
 
> Nope, the tools should be updated to cope with the new language rules.
 
> However, auto return type should be avoided in API-s
 
Agreed.
 
 
guinness.tony@gmail.com: Jun 26 04:30PM -0700

On Sunday, 24 June 2018 06:39:37 UTC+1, Alf P. Steinbach wrote:
> (args[1] == "--faux-text"? With_faux_text{}._ :
> With_stream_detection{}._), app::run();
> }
 
There are so many undeclared identifiers in that code soup that I cannot understand whatever "approach" it is that you are trying to convey.
Juha Nieminen <nospam@thanks.invalid>: Jun 27 05:40AM

> public:
> const char _{ '-' };
 
Is this intentional obfuscation?
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 08:24AM +0200

On 27.06.2018 07:40, Juha Nieminen wrote:
>> public:
>> const char _{ '-' };
 
> Is this intentional obfuscation?
 
It's a to me simplest possible and non-verbose conversion to a common
type for the two type-wise unrelated struct types, so that they can be
used in the same :?-expression:
 
(args[1] == "--faux-text"? With_faux_text{}._ :
With_stream_detection{}._), app::run();
 
I guess an alternative could be to derive them from a common base class,
but I didn't try that. The details of the rules for :? elude me. I have
to look them up every few years when I stubbornly write or by necessity
delve into some tricky :? code.
 
So in my humble opinion, better avoid those grayshade corners of the
language, and Keep It Super Simple™ and obviously valid. :)
 
 
Cheers!,
 
- Alf
David Brown <david.brown@hesbynett.no>: Jun 27 09:36AM +0200

On 27/06/18 08:24, Alf P. Steinbach wrote:
> delve into some tricky :? code.
 
> So in my humble opinion, better avoid those grayshade corners of the
> language, and Keep It Super Simple™ and obviously valid. :)
 
It is far, far better to Keep It Simple, Stupid - and use an "if". That
rule trumps pointless DRY complaints every time:
 
if (args[1] == "--faux-text") {
With_faux_text w;
app::run();
} else {
With_stream_detection w;
app::run();
}
 
If you are really desperate to avoid duplicating app::run() here, make a
template:
 
template<typename T>
void run_with(T with)
{
app::run();
}
 
if (args[1] == "--faux-text") {
run_with(With_faux_text());
} else {
run_with(With_stream_detection());
}
 
 
Don't use ?: when you really mean an "if" statement. Don't use the
comma operator when you really mean two successive statements. There
can be rare cases when they are a neat choice - but they are very rare.
 
A key reason for this is that the details of ?: and the comma operator
are not well known amongst many programmers. For example, for classes A
and B, the expression "A(), B()" will create anonymous temporaries of
the two types. But do you /know/, beyond any doubt, that the temporary
A object will still be alive when B is created? The answer is that it
will - but it is not obvious to many C++ programmers.
 
 
(However, your "_" trick for converting to a common type was
interesting. The naming could be improved, but it was a neat trick.)
Juha Nieminen <nospam@thanks.invalid>: Jun 27 10:59AM

> used in the same :?-expression:
 
> (args[1] == "--faux-text"? With_faux_text{}._ :
> With_stream_detection{}._), app::run();
 
I thought that there would be a simple explanation for that oddity,
but it appears that it's, indeed, used for even more obfuscation.
 
Even an experienced C++ programmer is going to have to examine
that expression for a while before he understands what's going on.
That's not good programming style.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 01:10PM +0200

On 27.06.2018 09:36, David Brown wrote:
> run_with(With_stream_detection());
> }
 
> Don't use ?: when you really mean an "if" statement.
 
The choice operator is in the language for a purpose, which happens to
be the exact purpose of the code.
 
 
> Don't use the
> comma operator when you really mean two successive statements.
 
In the presented code only a single statement will do.
 
If the comma is replaced with a ';', then cleanup will be performed be
the call to app::run() instead of after.
 
 
> There
> can be rare cases when they are a neat choice - but they are very rare.
 
This is one. ;-)
 
 
> the two types. But do you /know/, beyond any doubt, that the temporary
> A object will still be alive when B is created? The answer is that it
> will - but it is not obvious to many C++ programmers.
 
It better be. But it's an interesting debate: at what level of knowledge
of details can one put the lines between "C++ expert", "C++ programmer"
and "programmer sometimes using C++"? I think the line between expert
and just programmer is somewhere where the programmer knows the rules of
temporaries, that knowing that basic thing does not qualify as expert.
 
 
> (However, your "_" trick for converting to a common type was
> interesting. The naming could be improved, but it was a neat trick.)
 
Thank you. :)
 
Cheers!
 
- Alf
boltar@cylonHQ.com: Jun 27 11:34AM

On Wed, 27 Jun 2018 13:10:17 +0200
 
>> Don't use ?: when you really mean an "if" statement.
 
>The choice operator is in the language for a purpose, which happens to
>be the exact purpose of the code.
 
Its purpose is to return 1 of 2 possible values, not to replace a multi
command "if" block.
 
Having seen your example code in a number of your posts I think its safe to
classify you as a showboating coder - ie you deliberately obfuscate your code
simply to try and convince everyone how clever you are. However if you try and
be too clever you can end up looking like a fool who doesn't understand the
concept of appropriate use. Your asinine "auto main() -> int" in another post
was a classic example of this.
 
>and "programmer sometimes using C++"? I think the line between expert
>and just programmer is somewhere where the programmer knows the rules of
>temporaries, that knowing that basic thing does not qualify as expert.
 
IMO a C++ expert is someone who cares more about the language than he does
about actually solving problems. Most of us learn enough to get the job done
and pick up more along the way from other peoples code. Very few read
stroustrup from cover to cover mainly because we're too busy doing the job
we're paid to do and have better things to do at home.
 
Similarly I doubt you'd get many painters obsessing about their paint brushes,
they're more concerned with the painting.
Juha Nieminen <nospam@thanks.invalid>: Jun 27 12:19PM

> Having seen your example code in a number of your posts I think its safe to
> classify you as a showboating coder - ie you deliberately obfuscate your code
> simply to try and convince everyone how clever you are.
 
"Don't be clever" - Bjarne Stroustrup
 
He further clarifies: "My point was to discourage overly clever code because
"clever code" is hard to write, easy to get wrong, harder to maintain, and
often no faster than simpler alternatives because it can be hard to
optimize."
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 02:36PM +0200

On 27.06.2018 14:19, Juha Nieminen wrote:
> "clever code" is hard to write, easy to get wrong, harder to maintain, and
> often no faster than simpler alternatives because it can be hard to
> optimize."
 
I didn't see Boltar's comment because he's in my kill file.
 
And you're pretty close now, again.
 
Just a heads up.
 
 
- Alf
David Brown <david.brown@hesbynett.no>: Jun 27 02:46PM +0200

On 27/06/18 13:10, Alf P. Steinbach wrote:
>> }
 
>> Don't use ?: when you really mean an "if" statement.
 
> The choice operator is in the language for a purpose,
 
Yes it is.
 
> which happens to
> be the exact purpose of the code.
 
No it isn't.
 
The choice operator is part of C so that you can write things like:
 
x = (a < b) ? b : a;
 
It is part of C++ because it is part of C. It is certainly /not/ part
of the C++ language so that you can use it to do different things by
using constructors for different classes. That use is allowed because
it would be complicated to disallow it, not because it is a good idea.
 
 
>> Don't use the
>> comma operator when you really mean two successive statements.
 
> In the presented code only a single statement will do.
 
Logically, you meant two statements. Define a variable (from one of
your classes), then run the app.
 
There are lots of things you /can/ do in C or C++ - and often you can
use expressions for things that are logically separate statements. In a
fair amount of code you could replace many of the ";" with commas. No
one does, because it would be pointlessly confusing and non-idiomatic.
 
 
> If the comma is replaced with a ';', then cleanup will be performed be
> the call to app::run() instead of after.
 
It would in this particular case - but not if you wrote the code in a
more normal structure.
 
Your code is an interesting example of using obscure syntax - but it is
not a good way to write code.
 
 
>> There
>> can be rare cases when they are a neat choice - but they are very rare.
 
> This is one. ;-)
 
No, it is not - except from the viewpoint that it is an interesting
example. If your purpose was merely to investigate or illuminate such
possibilities, then it was clearly a good choice - if it was to write
good clear code, it failed.
 
> and "programmer sometimes using C++"? I think the line between expert
> and just programmer is somewhere where the programmer knows the rules of
> temporaries, that knowing that basic thing does not qualify as expert.
 
Ah, there we can agree - an interesting debate could be made from this.
At what point do you restrict your coding to make it easier to
understand for a wider proportion of programmers? Or do you write code
in a more advanced way, and restrict the programmers who work with it?
 
(In this case, there is nothing to be gained - except a talking point
and perhaps a little knowledge - from using an obscure structure. So
here a simpler structure would be better.)
 
 
>> (However, your "_" trick for converting to a common type was
>> interesting. The naming could be improved, but it was a neat trick.)
 
> Thank you. :)
 
Your next challenge is to re-write it using a std::variant as a way of
combining the two distinct classes :-)
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 03:06PM +0200

On 27.06.2018 14:46, David Brown wrote:
 
> Your next challenge is to re-write it using a std::variant as a way of
> combining the two distinct classes :-)
 
That's good, I didn't think of that.
 
But it's a library solution to what the core language already offers for
this case.
 
I don't think the ?: syntax is obscure; on the contrary, it's basic,
while `std::variant` gets into the more advanced territory, as I see it.
 
 
Cheers!,
 
- Alf
MrBoltarToYou@galactic.com: Jun 27 01:41PM

On Wed, 27 Jun 2018 14:36:19 +0200
>> often no faster than simpler alternatives because it can be hard to
>> optimize."
 
>I didn't see Boltar's comment because he's in my kill file.
 
Thats easily fixed as you can see. And the fact that you've killfiled me
demonstrates that you're not only a show off, but have a fragile ego too and
can't handle valid criticism. I hope I never have the misfortune to have to use
any code you wrote.
 
>And you're pretty close now, again.
 
I'm sure he's quakeing in his boots.
David Brown <david.brown@hesbynett.no>: Jun 27 04:02PM +0200

On 27/06/18 15:06, Alf P. Steinbach wrote:
> this case.
 
> I don't think the ?: syntax is obscure; on the contrary, it's basic,
> while `std::variant` gets into the more advanced territory, as I see it.
 
The ?: operator itself is standard, but unusual (compared to the other
operators) and programmers are often less familiar with it. In simple
cases it is common enough - for the sort of usage you have here, it /is/
obscure. It would also be banned by any decent coding standard - you
never allow short-circuit expressions that have side effects. So you
don't allow "A && B" if B has a side-effect - you write "if (A) { B; }".
The same goes for || and ?:.
 
 
Of course std::variant is advanced - it is C++17, and thus not available
(much less familiar) to many programmers. It was merely a suggestion of
an alternative idea for this sort of code - not because I thought it
would be a /good/ way to write it.
 
 
Writing fancy code like this can be a fun exercise, as long as you don't
mistake it for /real/ code. Being "smart" can help people learn and
give new ideas. Writing it in actual serious code is "smart-arse",
which is no longer a complement. It's like using Greek letters as extra
operators in C++ classes - it's fun, but highly unlikely to be good
coding practice.
 
 
And since people have been giving quotations, don't forget this one:
 
"Everyone knows that debugging is twice as hard as writing a program in
the first place. So if you're as clever as you can be when you write it,
how will you ever debug it? " (Brian Kernighan)
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 27 10:21AM -0400

On 06/27/2018 07:10 AM, Alf P. Steinbach wrote:
>> }
 
>> Don't use ?: when you really mean an "if" statement.
 
> The choice operator is in the language for a purpose, ...
 
Correct. In C, it allows you to do something that otherwise requires
multiple statements in a single expression. It should only be used when
multiple statements are disallowed, such as initializers, or conditions
in #if directives or if(), while(), do while(), and for() statements, or
the first and third parts of a for(). Even in those locations, it should
only be used if it's actually clearer than the alternative (which would,
generically, involve defining a function that contains those multiple
statements).
It's in C++ for backwards compatibility, but C++ provides a number of
alternatives that render it less necessary.
 
> ... which happens to
> be the exact purpose of the code.
 
Incorrect. As a general rule in C++, anytime you might be tempted to
write an if() or switch() statement that is that is directly or
indirectly connected to a type, you should consider the possibility of
using function overloading or inheritance and a virtual member function.
I think that's precisely the right solution in this case. This also
applies if you find yourself writing multiple catch() blocks for the
same try{} block, which is explicitly type-based.
 
>> Don't use the
>> comma operator when you really mean two successive statements.
 
> In the presented code only a single statement will do.
 
Which could call an overloaded function or a virtual member function.
 
>> There
>> can be rare cases when they are a neat choice - but they are very rare.
 
> This is one. ;-)
 
No, it isn't.
Manfred <noname@invalid.add>: Jun 27 06:03PM +0200

On 6/27/2018 3:06 PM, Alf P. Steinbach wrote:
> this case.
 
> I don't think the ?: syntax is obscure; on the contrary, it's basic,
> while `std::variant` gets into the more advanced territory, as I see it.
 
You may want to keep the ?: with a std::variant :-)
 
Posting the code because I am not 100% confident that move ctors are
guaranteed not to be called - I'm thinking of potential move of the
std::variant.
 
============
 
#include <iostream>
#include <string>
#include <variant>
 
 
class With_faux_text
{
public:
With_faux_text(With_faux_text&&) { std::cout << "move
With_faux_text" << std::endl; }
With_faux_text() { std::cout << "ctor With_faux_text" << std::endl; }
~With_faux_text() { std::cout << "dtor With_faux_text" <<
std::endl; }
};
 
class With_stream_detection
{
public:
With_stream_detection(With_stream_detection&&) { std::cout << "move
With_stream_detection" << std::endl; }
With_stream_detection() { std::cout << "ctor With_stream_detection"
<< std::endl; }
~With_stream_detection() { std::cout << "dtor
With_stream_detection" << std::endl; }
};
 
using StreamContext = std::variant<std::monostate, With_faux_text,
With_stream_detection>;
 
class App
{
public:
static void run()
{
std::cout << "App::run()" << std::endl;
}
};
 
StreamContext createContext(int argc, char* argv[])
{
return (2 <= argc && std::string(argv[1]) == "--faux-text") ?
StreamContext{std::in_place_type<With_faux_text>} :
StreamContext{std::in_place_type<With_stream_detection>};
}
 
int main(int argc, char *argv[])
{
StreamContext context = createContext(argc, argv);
 
App::run();
 
}
 
 
==============
 
./a.out --faux-text
ctor With_faux_text
App::run()
dtor With_faux_text
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 09:45PM +0200

> snip
 
Your third identify to be killfiled by me.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 10:54PM +0200

On 27.06.2018 16:02, David Brown wrote:
> operators) and programmers are often less familiar with it. In simple
> cases it is common enough - for the sort of usage you have here, it /is/
> obscure.
 
How can a single ?: be obscure?
 
Beginners learn it, very early on, and you say some experienced
programmers you've encountered find it challenging?
 
I find that claim hard to believe.
 
 
> never allow short-circuit expressions that have side effects. So you
> don't allow "A && B" if B has a side-effect - you write "if (A) { B; }".
> The same goes for || and ?:.
 
Yes, it's /generally/, often, maybe even usually, a Bad Idea™ to express
side effects with boolean operators, because if anything else isn't
evident, one expects such an expression to just compute a boolean value.
 
But
 
1. it isn't /always/ bad to do that with boolean expressions, and
2. a choice expression isn't like a boolean expression.
 
Regarding (1), in C++ the core language features are often just used to
implement higher level features that we know from other languages. E.g.
preprocessor directives and conventions about filenames and contents,
are used to implement modules. In that spirit shortcut boolean
expressions are sometimes used to implement bail-out from a sequence of
operations that indicate success/failure via boolean returns:
 
// A. OK for me
const bool success = a() and b() and c() and d() and e();
 
which would be banned by your "decent coding standard", instead of the
more complex exception based code
 
// B. Gah!
bool success = true;
try
{
a(); b(); c(); d(); e();
}
catch( exception const& )
{
success = false;
}
 
or the code that a literal interpretation of what you write, would yield:
 
// C. Double gah, kill me.
bool success = a();
if( success )
{
success = b();
if( success )
{
success = c();
if( success )
{
success = d();
if( success )
{
success = e();
}
}
}
}
 
Again, compare that to
 
// OK for me
const bool success = a() and b() and c() and d() and e();
 
So "It would also be banned by any decent coding standard - you
never allow short-circuit expressions that have side effects." appears
to mean that the coding standards that you regard as decent, require the
fantastic ugliness and awkwardness of (B) or (C) above.
 
Regarding (2), that a choice expression isn't like a boolean expression,
choice expressions are IME much more commonly used for side effects than
boolean expressions are, especially where a result value is used.
 
 
 
> (much less familiar) to many programmers. It was merely a suggestion of
> an alternative idea for this sort of code - not because I thought it
> would be a /good/ way to write it.
 
Yes, considering all possibilities is often useful.
 
If for nothing else, one might learn something from the exercise. :)
 
 
> mistake it for /real/ code. Being "smart" can help people learn and
> give new ideas. Writing it in actual serious code is "smart-arse",
> which is no longer a complement.
 
I don't get what's fancy or "smart" about it.
 
Exactly what is fancy? Is it the conditional expressions? Do the
programmers you know have problems with conditional expressions?
 
 
> It's like using Greek letters as extra
> operators in C++ classes - it's fun, but highly unlikely to be good
> coding practice.
 
But what is it that's Greek to you, or that you suspect would be Greek
to most others, in the code?
 
I see nothing but basics:
 
RAII, conditional, comma expression. Easy peasy.
 
 
 
> "Everyone knows that debugging is twice as hard as writing a program in
> the first place. So if you're as clever as you can be when you write it,
> how will you ever debug it? " (Brian Kernighan)
 
As a counter example, the reason that we (C++ programmers) use RAII
isn't because RAII is easier to debug than plain if-else's and sequences
and `goto` a common cleanup.
 
We use it because it's easier to understand and analyze, to prove
correctness of, due to the simple guarantees.
 
I am not sure about the debuggability of the code as I wrote it, though.
Maybe the ?: expression and comma expression should be written with each
part on its own line, maybe that would help a debugger show what's being
executed. That research will have to wait though (for me)...
 
 
Cheers!,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 10:56PM +0200

On 27.06.2018 16:21, James Kuyper wrote:
>>> can be rare cases when they are a neat choice - but they are very rare.
 
>> This is one. ;-)
 
> No, it isn't.
 
Well, let's compare your virtual member function code to the one I
presented, when the codes do the same with same exception guarantees.
 
Cheers!
 
- Alf
ram@zedat.fu-berlin.de (Stefan Ram): Jun 27 08:29PM

Tools like Doxygen copy the head of a function definition
to double as documentation:
 
Synopsis
int f();
 
, and, of course, the "Synopsis" gives us the return type.
 
But what about a function definition like:
 
auto f(){ return 7; }
 
? A synopsis like
 
Synopsis
auto f();
 
is hardly helpful. So should we avoid the auto return type
for functions which are part of an API for this reason?
ram@zedat.fu-berlin.de (Stefan Ram): Jun 27 08:37PM

>It's in C++ for backwards compatibility,
 
It allows you to directly transcribe a "mathematical"
definition like
 
.-
| n * f( n - 1 ), if n is not 0
f( n ) = <
| 1, , otherwise.
'-
 
which becomes
 
n ? n * f( n - 1 ): 1
 
, and it allows you to express your ideas in code when you
happen to think in terms of a case discrimination as shown.
 
"Express ideas directly in code" - C++ Core Guidelines
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jun 26 08:50PM -0700

On 6/26/2018 7:06 AM, Rick C. Hodgin wrote:
> examine the headers.  I post only from Eternal September or Google
> News, and from Indianapolis, IN.
 
> The imposter here posted from an "en-GB" timezone using Giganews.
 
I hope all of the mimicry could be halted sometime....
Lynn McGuire <lynnmcguire5@gmail.com>: Jun 26 09:01PM -0500

"Modern C++ for C Programmers: part 1"
https://ds9a.nl/articles/posts/c++-1/
 
Lynn
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: