Tuesday, March 10, 2020

Digest for comp.lang.c++@googlegroups.com - 23 updates in 4 topics

Daniel <danielaparker@gmail.com>: Mar 09 06:24PM -0700

On Monday, March 9, 2020 at 6:45:37 PM UTC-4, Maciej Sobczak wrote:
 
> > 1: Everyone agrees that it is impossible for a normal individual to
> > understand all C++
 
> I have not seen any agreement on this (it's just your perspective). I would > rather say that it is not *necessary* for a normal individual to understand > all of C++. And nobody expects that.
 
It's not so much that C++ has so many things, but rather, that it lacks all coherence, any vision, that it's one ad hoc thing after another. For what reason do we have
 
std::string s = "foo";
 
const char* p = s.c_str(); // explicit, good
but
std::string_view sv = s; // implicit, bad for all the reasons we have c_str()
 
and
 
s = p; // Seems safe enough
but
s = std::string(sv); // Why?
 
And collision between uniform initialization and initializer list. Why? The
committee had to have known that, when they voted for it.
 
And why introduce <system_error> requiring using _global objects_ for
identifying error categories? Uniqueness of address doesn't work with DLL's,
probably not shared libraries either, and the committee would have known that.
 
The list is endless.
 
Daniel
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 10 02:43AM +0100

On 10.03.2020 02:24, Daniel wrote:
 
> const char* p = s.c_str(); // explicit, good
> but
> std::string_view sv = s; // implicit, bad for all the reasons we have c_str()
 
For convenience when `std::string_view` is a formal argument type.
 
This lets you define /one/ function, no overloads, that handles just
about any non-zero-terminated string.
 
 
 
> s = p; // Seems safe enough
> but
> s = std::string(sv); // Why?
 
Yah. That one's ugly as heck.
 
 
> And collision between uniform initialization and initializer list. Why?
 
Agree about that also. It's botched. Bjarne's vision was nice, and I
believe it was the committee that messed it totally up.
 
 
> The committee had to have known that, when they voted for it.
 
Politics I gather, combined with weak leadership.
 
I think it's the same that happens in a lot of municipalities in Norway.
The political leadership avoids taking on difficult issues. The
bureaucrats then think that they just /have/ to make the decisions on
behalf of the politicians, and they get away with it. However, a
bureaucrat generally sees only his or her little very narrow and short
slice of reality, and additionally, is often constrained by rules
interpreted by the letter. Written rules don't have intelligence. The
result is ungood.
 
 
> identifying error categories? Uniqueness of address doesn't work with DLL's,
> probably not shared libraries either, and the committee would have known that.
 
> The list is endless.
 
The lack of support for dynamic libraries is an open large wound in the
language, so to speak. IMO.
 
But which model to go for: Windows DLLs (very encapsulated), Linux
shared libraries (like static libraries essentially, just dynamic), or
maybe some third model defined by the committee, since there is strong
precedence for not standardizing existing practice, but rather invent?
 
Happily with C++20 there will be a `std::pi` (of course not the existing
practice M_PI, from the Posix standard, but a pi value, hurray).
 
And type safe text formatting based on format strings. They managed to
dirty it by adding locale support. But I was wrong in thinking it was
correct, as people had asserted, that they'd really sabotaged that
library: by default locales aren't used, the use has to be requested,
because the formatting is defined in terms of C++17 `std::to_chars`.
 
So all's not lost. But the half-baked C++20 co-routines, which aren't
really co-routines anyway but more like continuations, that's bad. And
the fragile and inefficient ranges library, with its
yet-another-domain-specific-sub-language-to-learn and `i(di)ota` func. Argh.
 
- Alf
Daniel <danielaparker@gmail.com>: Mar 09 08:11PM -0700

On Monday, March 9, 2020 at 9:43:50 PM UTC-4, Alf P. Steinbach wrote:
>> known that.
 
> The lack of support for dynamic libraries is an open large wound in the
> language, so to speak.
 
But that aside, why require equality of _addresses_? Equality of type_info
doesn't require equality of addresses, only that they be the "same", my
understanding is that MSVC satisfies that sameness requirement with string
equality. So why require equality of addresses with error categories? I mean,
the issue with uniqueness of address is understood, it's known.
 
Daniel
Daniel <danielaparker@gmail.com>: Mar 09 08:47PM -0700

On Monday, March 9, 2020 at 6:39:40 AM UTC-4, David Brown wrote:
 
> C++ does suffer from a some serious issues, however. Backwards
> compatibility can make things more awkward or bulky than it should be
> (someone mentioned EBCDIC, for example).
 
Coexisting with EBCDIC is only an issue because C++ lacks proper abstractions for byte sequences and text, and conversion utilities between them. In Java I can read any number of flavors of EBCDIC as bytes, convert those bytes into a unicode string, work with that string, and convert the result back to EBCDIC bytes. There's been prior art for that for a long long time, but C++ still doesn't have it.
 
Daniel
Ian Collins <ian-news@hotmail.com>: Mar 10 09:10PM +1300

On 10/03/2020 00:00, Bart wrote:
>> ignoring) that.
 
> Until you make a typo that would be thrown out by a C compiler, but is
> legal in C++ and does something you don't expect.
 
Which you are very unlikely to do.
 
> Or if it is not legal in C++ either, it generates a 300-line error
> message that you can't make head nor tail of.
 
Which won't happen with C and a tiny bit more.
 
You know that already, but like Jacob, you choose to ignore it.
 
--
Ian.
David Brown <david.brown@hesbynett.no>: Mar 10 11:11AM +0100

On 10/03/2020 09:10, Ian Collins wrote:
>> message that you can't make head nor tail of.
 
> Which won't happen with C and a tiny bit more.
 
> You know that already, but like Jacob, you choose to ignore it.
 
Just yesterday, I had a single typo that lead to hundreds of error
messages in a different file - there was no indication of where the real
error lay. That was a missing semicolon in a header - and it was all C,
no C++ in sight. The idea that confusing or unhelpful error messages is
purely a C++ phenomenon is just nonsense.
 
C++ is a bigger language, and you can do a lot more in a few lines, so
the scope for long error messages is greater. That just means you have
to be a bit smarter, and use better tools, when working with it. A good
IDE will help you navigate, and help you figure out which of the error
messages are most relevant. And compilers have been getting better at
this - gcc's error messages have become steadily more relevant, steadily
better at pointing out what is /actually/ wrong, and steadily better at
giving suggestions for corrections.
 
Also, one of the motivations for newer C++ features like concepts and
modules is to make it easier to find problems and simplify error
messages. Concepts mean you'll get the messages when you define
templates, rather than when you use them.
David Brown <david.brown@hesbynett.no>: Mar 10 11:29AM +0100

On 10/03/2020 04:47, Daniel wrote:
> string, and convert the result back to EBCDIC bytes. There's been
> prior art for that for a long long time, but C++ still doesn't have
> it.
 
And the reason for that lack of abstraction is backwards compatibility,
from C. That is not an excuse, of course - C++ should be working more
towards a separation here (IMHO). There has been progress (std::byte,
and char8_t are steps in the right direction). The trouble is, in order
to do this properly, you'd need to break a good deal of code.
 
In my ideal language, you'd have types:
 
"char8_t" is a code unit for utf-8 data. It can hold any one ASCII
character, and part of other utf-8 characters. Strings are stored in
arrays of char8_t.
 
"char32_t" is a code unit for utf-32 data.
 
There is no "char", and certainly not the meaningless "signed char",
"unsigned char" types, or the underspecified "wide char" junk. There is
no utf-16 or UCS16 - these encodings sounded good on creation, but were
dead-ends. (Of course you'd have libraries for importing and exporting
utf-16 and other encodings, but they would not be fundamental types in
the language.)
 
There would be types "raw8_t", "raw16_t", etc. These are for untyped
data sequences and low-level access. They would be allowed to alias any
other types (like "unsigned char" today), and used for moving data
around. There would be no arithmetic operations on them or comparisons
other than == and !=. (It was a mistake to allow operations on std::byte.)
 
You'd have signed and unsigned integer types of different sizes, but
these would be entirely independent of the character types and raw types.
 
 
How you could get there from today's C++ (assuming other people agreed
with the aim!), I have no idea - it would involve massive changes and
incompatibilities in existing code.
Bart <bc@freeuk.com>: Mar 10 11:02AM

On 10/03/2020 10:11, David Brown wrote:
> error lay. That was a missing semicolon in a header - and it was all C,
> no C++ in sight. The idea that confusing or unhelpful error messages is
> purely a C++ phenomenon is just nonsense.
 
But this is hundreds of different error messages, rather than hundreds
of lines of the same message.
 
The start point will be the first error message; no point in looking at
the rest until the first has been dealt with.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 10 12:30PM +0100

On 10.03.2020 04:11, Daniel wrote:
> understanding is that MSVC satisfies that sameness requirement with string
> equality. So why require equality of addresses with error categories? I mean,
> the issue with uniqueness of address is understood, it's known.
 
It /looks/ like `system_error` was lifted from the Boost library, where
the address comparison was just a default for error categories that
lacked id's, and that then for the standard library id's were removed.
 
<url:
https://www.boost.org/doc/libs/1_69_0/libs/system/doc/html/system.html#ref_nonvirtuals>
 
Given the very Posix'y nature of `std::runtime_error` I'd guess the
(assumed) id removal is just underhanded or even inadvertent Windows
sabotage. For the "inadvertent" I guess the reasoning went like this:
 
1. BTW let's fix this, those random 64-bit compile time id's are
kludges. Can we use more robust & safe 128-bit UUIDs? Maybe?
2. Hey, id's are not necessary, we can just use addresses. I tested this
now [not mentioned: in Linux] and simply removed id's and it worked fine!
3. What a jolly good idea, a SIMPLIFICATION! Let's do that, yes.
 
Same as changing the return type of `std::filesystem::path::u8string` in
C++20 to incompatible: it's only a problem in Windows, not in *nix.
 
 
- Alf
David Brown <david.brown@hesbynett.no>: Mar 10 12:58PM +0100

On 10/03/2020 12:02, Bart wrote:
>> purely a C++ phenomenon is just nonsense.
 
> But this is hundreds of different error messages, rather than hundreds
> of lines of the same message.
 
Yes, the list I got had a large number of different error messages - and
none of them were from the file with the actual typo.
 
 
> The start point will be the first error message; no point in looking at
> the rest until the first has been dealt with.
 
Usually you can get a good idea by looking at the first and the last
error message - that applies equally to C and C++.
Daniel <danielaparker@gmail.com>: Mar 10 08:35AM -0700

On Tuesday, March 10, 2020 at 7:30:28 AM UTC-4, Alf P. Steinbach wrote:
> lacked id's, and that then for the standard library id's were removed.
 
> <url:
> https://www.boost.org/doc/libs/1_69_0/libs/system/doc/html/system.html#ref_nonvirtuals>
 
That was introduced into boost in 1_69_0, though
 
boost 1_69_0: rhs.id_ == 0? this == &rhs: id_ == rhs.id_
 
boost 1_68_0: &lhs == &rhs;
 
And from the release notes to 1_69_0:
 
"error_category now has a constructor that accepts a 64 bit identifier,
enabling distinct category objects to compare equal."
 
The 64 bit identifier to be generated randomly by the implementor.
 
Daniel
Jorgen Grahn <grahn+nntp@snipabacken.se>: Mar 10 06:55AM

On Mon, 2020-03-09, Frederick Gotham wrote:
> retrieve the first line of text from its stdout. If any kind of
> error takes places, the function will simply return an empty
> string. No exceptions will be thrown.
...
 
> I will give a default timeout of 5 seconds for the second program to finish.
 
Why? It's an unusual feature and complicates things.
 
 
> #include <string> /* string */
 
> std::string Run_Command_string(std::string const &str_prog,
> unsigned const timeout = 5u) noexcept
 
Why not chrono here, so you don't have to wonder if it's 5 s or 5 ms?
 
...
> std::getline(ip,retval);
 
> /* Now just discard the rest of the output */
> for (string tmp; std::getline(ip,tmp); ) { /* Do Nothing */ }
 
This means you're waiting for the whole input before you process the
first line, and the whole input may be infinite, or take days to
produce.
 
The Unix way to handle this is (I think) to close the pipe and wait
for the child to notice (via SIGPIPE at least) and die. I don't know
what boost::process does to support it, or what would work on Windows.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 02:11AM -0700

On Tuesday, March 10, 2020 at 6:55:40 AM UTC, Jorgen Grahn wrote:
 
> > I will give a default timeout of 5 seconds for the second program to finish.
> Why? It's an unusual feature and complicates things.
 
 
On one of the embedded-Linux devices I'm developing, you have to stop a system daemon before you can make a data request to the lens module. Sometimes it takes a few seconds for the daemon to stop, so I give it a maximum of 10 seconds before I consider it to have frozen or crashed.
 
 
> > std::string Run_Command_string(std::string const &str_prog,
> > unsigned const timeout = 5u) noexcept
 
> Why not chrono here, so you don't have to wonder if it's 5 s or 5 ms?
 
 
Yeah but wouldn't I need to turn it into a template function? Something like:
 
template<class Rep, class Period>
std::string Run_Command_string(std::string const &str_prog, std::chrono::duration<Rep,Period> const &timeout) noexcept
 
 
> This means you're waiting for the whole input before you process the
> first line, and the whole input may be infinite, or take days to
> produce.
 
 
That's why I've got the timeout. Actually now that I think of it, I could get the Reader thread to immediately notify the main thread when it's got the first line.
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 05:28AM -0700

On Tuesday, March 10, 2020 at 6:55:40 AM UTC, Jorgen Grahn wrote:
 
> This means you're waiting for the whole input before you process the
> first line, and the whole input may be infinite, or take days to
> produce.
 
 
 
Here's my third attempt:
 
 
/* The next function is to run a command and capture its
first line of stdout. On failure, returns empty string. */
std::string Run_Command_string(std::string const &str_cmd, unsigned const timeout = 5u) noexcept
{
using std::string;
namespace bp = boost::process;
 
bp::ipstream *p_ip = nullptr;

try
{
string retval;
 
p_ip = new bp::ipstream; /* For capturing stdin from child process */
 
bp::child c(bp::search_path("sh"), "-c", str_cmd, bp::std_in.close(), bp::std_out > *p_ip, bp::std_err > bp::null);
 
boost::mutex mutex_for_messaging;
bool bHave_first_line_yet = false;
boost::mutex::scoped_lock lock_for_condition(mutex_for_messaging);
boost::condition_variable have_first_line_yet;
 
//cout << "About to start Reader thread" << endl;

/* Start second thread here to capture the first line of stdout */
boost::thread reader(
[=, p_ip, &retval, &have_first_line_yet, &bHave_first_line_yet]
{
try
{
/* Retain the first line of text */
try
{
std::getline(*p_ip,retval);
}
catch (...)
{
retval.clear();
}
 
bHave_first_line_yet = true;
have_first_line_yet.notify_one(); /* The main thread is doing 'wait_for' */

/* ==== DANGER DANGER DANGER ==== Run_Command_string might have returned by this point ==== DANGER ==== DANGER */
/* so do not use retval, have_first_line_yet, bHave_first_line_yet past this point */
 
try
{
/* Now just discard the rest of the output */
for (string tmp; std::getline(*p_ip,tmp); ) { /* Do Nothing */ }
}
catch (...)
{
/* Do Nothing */
}

delete p_ip;
}
catch (...)
{
/* Do Nothing */
}
}
);

bool const did_not_timeout = (boost::cv_status::no_timeout == have_first_line_yet.wait_for(lock_for_condition, boost::chrono::seconds(timeout)));
 
if ( did_not_timeout && bHave_first_line_yet )
{
/* We got the first line within the timeout! :-) */

reader.detach(); /* Allow it to continue reading lines from the child program */
 
//cout << "Finished in time: Reader thread" << endl;
 
return retval;
}
else
{
//cout << "TIMEOUT: Reader thread" << endl;

/* Program has frozen, so just return an empty string */
c.terminate();
reader.interrupt();
reader.detach();
}
}
catch (...)
{
/* Do Nothing */
}

delete p_ip; /* Is there a chance that this could be a second deletion? */

return string();
}
 
 
I have tested this on Linux with a sample program:
 
void Do(void)
{
static std::mutex mtx;

std::string const &retval1 = Run_Command_string("find / | grep bin");
mtx.lock(); cout << "==== ONE ==== " << retval1 << endl; mtx.unlock();

std::string const &retval2 = Run_Command_string("find / | grep usr");
mtx.lock(); cout << "==== TWO ==== " << retval2 << endl; mtx.unlock();

std::string const &retval3 = Run_Command_string("find / | grep lib");
mtx.lock(); cout << "==== TR3 ==== " << retval3 << endl; mtx.unlock();
}
 
#include <vector>
 
auto main(void) -> int
{
std::vector<std::thread*> vec;

for (unsigned i = 0; i != 45; ++i)
{
vec.push_back(new std::thread(Do));
}

for (;;) {}
}
 
Of course there's a few more things to take into account, such as whether the main thread should wait for all threads to finish (or to kill them) before returning from main.
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 05:40AM -0700

On Tuesday, March 10, 2020 at 12:28:22 PM UTC, Frederick Gotham wrote:
 
> delete p_ip; /* Is there a chance that this could be a second deletion? */
 
 
This definitely should be there. If it should be anywhere it should be right beside the call to thread::interrupt, but even then it isn't certain that the Reader thread hasn't already deleted it.
cdalten@gmail.com: Mar 10 05:51AM -0700

On Tuesday, March 10, 2020 at 5:28:22 AM UTC-7, Frederick Gotham wrote:
 
> for (;;) {}
> }
 
> Of course there's a few more things to take into account, such as whether the main thread should wait for all threads to finish (or to kill them) before returning from main.
 
I think my IQ dropped 20 points after reading this crap.
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 06:07AM -0700


> I think my IQ dropped 20 points after reading this crap.
 
 
I know a guy who had his corpus callosum in his brain(s) severed so that he could think about two things independently at once without having one idea interfere with the other. (Effectively giving him two separate 'threads' of thought).
 
I can't tell you more about him though because it's highly illegal to practise this surgery on people for experimental purposes (even if you are indeed a competent and fully-licensed medical surgeon).
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 06:57AM -0700

On Tuesday, March 10, 2020 at 12:28:22 PM UTC, Frederick Gotham wrote:
 
> Here's my third attempt:
 
 
I might be going a little far with the static array of bits to keep track of deletions, but here's my fourth attempt:
 
/* The next function is to run a command and capture its
first line of stdout. On failure, returns empty string. */
std::string Run_Command_string(std::string const &str_cmd, unsigned const timeout = 5u) noexcept
{
/* ====== Determine all the limits and integer types in this block ======= */
typedef uint64_t IntBits;
static std::size_t constexpr maxcalls = 1000000u; /* 1 million (must be divisable by width of IntBits) */
static uint_fast32_t counter = 0; /* 32-Bit can do up to 4 billion */
/* ================= END OF BLOCK ======================================== */
 
static std::size_t constexpr w = sizeof(IntBits) * CHAR_BIT; /* Assume no padding bits inside integer types */
 
static IntBits bits[maxcalls / w] = {}; /* Starts out all zero */
 
static boost::mutex mtx_bits;

decltype(counter) local_counter;
 
{ /* This is a deliberate scope block */
boost::mutex::scoped_lock scpl(mtx_bits);
 
local_counter = counter;
bits[counter / w] |= static_cast<IntBits>(1) << (counter % w);
++counter;
}

using std::string;
namespace bp = boost::process;
 
bp::ipstream *p_ip = nullptr;

try
{
string retval;
 
p_ip = new bp::ipstream; /* For capturing stdin from child process */
 
bp::child c(bp::search_path("sh"), "-c", str_cmd, bp::std_in.close(), bp::std_out > *p_ip, bp::std_err > bp::null);
 
boost::mutex mutex_for_messaging;
bool bHave_first_line_yet = false;
boost::mutex::scoped_lock lock_for_condition(mutex_for_messaging);
boost::condition_variable have_first_line_yet;
 
//cout << "About to start Reader thread" << endl;

/* Start second thread here to capture the first line of stdout */
boost::thread reader(
[=, p_ip, local_counter, &retval, &have_first_line_yet, &bHave_first_line_yet]
{
try
{
/* Retain the first line of text */
try
{
std::getline(*p_ip,retval);
}
catch (...)
{
retval.clear();
}
 
bHave_first_line_yet = true;
have_first_line_yet.notify_one(); /* The main thread is doing 'wait_for' */

/* ==== DANGER DANGER DANGER ==== Run_Command_string might have returned by this point ==== DANGER ==== DANGER */
/* so do not use retval, have_first_line_yet, bHave_first_line_yet past this point */
 
try
{
/* Now just discard the rest of the output */
for (string tmp; std::getline(*p_ip,tmp); ) { /* Do Nothing */ }
}
catch (...)
{
/* Do Nothing */
}

{
boost::mutex::scoped_lock scpl(mtx_bits);

IntBits const mask = static_cast<IntBits>(1) << (local_counter % w);

if ( bits[local_counter / w] & mask )
{
delete p_ip;

bits[local_counter / w] &= ~mask;
}
}
}
catch (...)
{
/* Do Nothing */
}
}
);

bool const did_not_timeout = (boost::cv_status::no_timeout == have_first_line_yet.wait_for(lock_for_condition, boost::chrono::seconds(timeout)));
 
if ( did_not_timeout && bHave_first_line_yet )
{
/* We got the first line within the timeout! :-) */

reader.detach(); /* Allow it to continue reading lines from the child program */
 
//cout << "Finished in time: Reader thread" << endl;
 
return retval;
}
else
{
//cout << "TIMEOUT: Reader thread" << endl;

/* Program has frozen, so just return an empty string */
c.terminate();
reader.interrupt();
reader.detach();
 
{ /* This is a deliberate scope block */
boost::mutex::scoped_lock scpl(mtx_bits);

IntBits const mask = static_cast<IntBits>(1) << (local_counter % w);

if ( bits[local_counter / w] & mask )
{
delete p_ip;

bits[local_counter / w] &= ~mask;
}
}
}
}
catch (...)
{
/* Do Nothing */
}

return string();
}
cdalten@gmail.com: Mar 10 07:07AM -0700

On Tuesday, March 10, 2020 at 6:57:28 AM UTC-7, Frederick Gotham wrote:
> }
 
> return string();
> }
 
Not that I should encourage this shutout, but the following line that you commented out...
 
//cout << "TIMEOUT: Reader thread" << endl;
 
Is kind of incorrect because error messages on Linux are unbuffered. And again, you would have only known his had you taken my advice and read the book "Advanced Programming in the Unix Environment" by the late Dr. Stevens.
 
And again, I think my IQ dropped 20 points after reading this crap.
queequeg@trust.no1 (Queequeg): Mar 10 11:37AM


> While there may be small differences between races these are dwarfed by
> the differences within races.
 
It's true, but I was refering to:
 
"You honestly think that ethnicity and race are somehow linked to
intelligence?"
 
Studies show that, to some extent, it is.
 
--
https://www.youtube.com/watch?v=9lSzL1DqQn0
Bo Persson <bo@bo-persson.se>: Mar 10 01:08PM +0100

On 2020-03-10 at 12:37, Queequeg wrote:
 
> "You honestly think that ethnicity and race are somehow linked to
> intelligence?"
 
> Studies show that, to some extent, it is.
 
No, the studies show that better education is well correlated to good
results on IQ tests.
 
 
If you, for example, were never taught how to read, you will score
really badly.
cdalten@gmail.com: Mar 10 05:46AM -0700

On Tuesday, March 10, 2020 at 5:08:37 AM UTC-7, Bo Persson wrote:
> results on IQ tests.
 
> If you, for example, were never taught how to read, you will score
> really badly.
 
Maybe. But I can think of one exception. One of histories greatest Mathematicians never really had an education. This was evident in his proof writing. Or lack thereof. But this guy, just like Euler, made significant contributions to almost every branch of Mathematics.
 
According to one of the Professor's at Harvard who worked with him, at the age of 21, he was proving three theorems a day.
"Öö Tiib" <ootiib@hot.ee>: Mar 10 01:06AM -0700

On Monday, 9 March 2020 11:54:32 UTC+2, David Brown wrote:
> you'd dislike other rules too, and for equally good reasons.) Most
> programmers work on the projects they are paid to work on and told to
> work on, rather than projects they want to work on.
 
I dislike deliberate usage of assignments in conditionals that are
actually confusing ... like if(p=getP()). The if(getP()==p) or
if(p==getP()) are both fine C++ for me.
 
Probable typos in usage of operators = and == are diagnosed by
majority of compilers and by lot of other tools. When reasonable
proposals of discarding pointless rule and to set up tool-chain
properly instead are rejected then it is not project for me. I am
more profitable participant in other projects. Other people may be are
different and that is normal.
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: