Thursday, August 29, 2019

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

Melzzzzz <Melzzzzz@zzzzz.com>: Aug 29 02:36AM

> he also spoke about the history of systems programming, how C became the
> "default" systems programming language, what features of Rust gives it
> an edge over C, and much more."
 
Rust is nowhere near C. Actually, nowhere near C++. It is nice language,
but not for low level programming. During years they ditched GC and most
of the things that cripples determinism and performance, it is ok, but
without pointer arithmetic and null pointers it is high level language.
Having to convert pointer to int and back in order to perform arithmetic
is worse that doing it in assembler.
But what Rust got it right is error handling, much better than
excpetions. But not having inheritance and forbidding two mutable
references to distinct array elements is stupid. Also no tail recursion
optimisation and no way to disable array checks.
 
 
 
--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
David Brown <david.brown@hesbynett.no>: Aug 29 11:02AM +0200

On 29/08/2019 04:36, Melzzzzz wrote:
> without pointer arithmetic and null pointers it is high level language.
> Having to convert pointer to int and back in order to perform arithmetic
> is worse that doing it in assembler.
 
That sounds terrible. (I am not very familiar with Rust.)
 
> But what Rust got it right is error handling, much better than
> excpetions. But not having inheritance and forbidding two mutable
> references to distinct array elements is stupid.
 
I have worked with a C-like language which had that many of that kind of
restriction (XC for the XMOS microcontrollers, if anyone is curious).
For a lot of code, it can be helpful - it allowed the compiler to find
lots of situations that could be problematic, especially in heavily
threaded and parallel code. But you invariably had situations where the
restrictions were too much - you needed shared access, or whatever, in
cases where you know they are safe. This typically lead to inline
assembly code to get round the safety limitations imposed by the
language and compiler - that was /not/ a good situation!
 
> Also no tail recursion optimisation and no way to disable array checks.
 
Surely tail recursion optimisation is just a matter of the compiler? C
and C++ don't have any mention of such optimisations in their standards,
but a compiler can do it as long as the code works under the "as if"
rule. Does the same not apply to Rust?
 
As for array checks, again I would think a compiler could elide a fair
number of them, reducing the cost of having them on all the time.
 
 
One thing that I gather Rust does well, that C++ has trouble with, is
that when you do the Rust equivalent of std::move'ing something, any
attempt to use the moved-from object is flagged by the compiler. I
think that would be good to spot in C++.
BGB <cr88192@gmail.com>: Aug 29 05:14AM -0500

On 8/28/2019 4:11 PM, Lynn McGuire wrote:
> he also spoke about the history of systems programming, how C became the
> "default" systems programming language, what features of Rust gives it
> an edge over C, and much more."
 
How about, instead:
We take C;
We add some features to support things like bounds-checked arrays and
similar;
We mostly call it done.
 
 
Many past variants of bounds-checked arrays did funky things with the
syntax, which is a problem if one wants to be able to make it work in a
compiler without support for this feature (eg: via non-convoluted use of
defines).
 
My thought is, say:
_BoundsCheck int *arr;
Which behaves sorta like "int[] arr;" in Java or similar.
 
Then it is given a shorthand in a header (eg: bounded), which becomes
no-op if the compiler doesn't support it.
 
Otherwise, it behaves mostly like a normal pointer, apart from potential
runtime bounds checking, and a different internal representation. May
decay into a normal pointer, potentially with a warning.
 
 
While at it, something like a standardized header for accessing
misaligned and explicit endianess values would be nice.
 
eg:
uint32_t getuint32le(void *ptr);
void setint32le(void *ptr, int32_t val);
...
Where: le: little endian, be: big endian, no suffix: native endian.
And, these functions work regardless of alignment.
 
This being semi-common boilerplate one either needs to copy around or
reimplement fairly often (and for which the optimal way to do these
varies between compilers; and with some dependence on target architecture).
 
 
Ian Collins <ian-news@hotmail.com>: Aug 29 10:21PM +1200

On 29/08/2019 21:02, David Brown wrote:
> that when you do the Rust equivalent of std::move'ing something, any
> attempt to use the moved-from object is flagged by the compiler. I
> think that would be good to spot in C++.
 
clang-tidy does a pretty good job with "bugprone-use-after-move"
<https://clang.llvm.org/extra/clang-tidy/checks/bugprone-use-after-move.html>
 
--
Ian.
David Brown <david.brown@hesbynett.no>: Aug 29 01:24PM +0200

On 29/08/2019 12:21, Ian Collins wrote:
>> think that would be good to spot in C++.
 
> clang-tidy does a pretty good job with "bugprone-use-after-move"
> <https://clang.llvm.org/extra/clang-tidy/checks/bugprone-use-after-move.html>
 
Yes, I saw that after googling a bit.
 
I would have thought, however, that pretty much any use (other than
assignment of some sort) of a named object after it is moved, is likely
to be a bug. And it is therefore something that could be warning about
by default.
 
 
#include <memory>
 
extern int a, b, c;
 
 
void foo(void) {
auto p = std::make_unique<int>(3);
a = *p;
auto q = std::move(p);
b = *q;
c = *p;
}
 
 
Both clang and gcc are smart enough to move the value 3 directly into
"a" and "b", and if the last line is omitted, they can remove the call
to "new" (at least in their trunk versions). Both are smart enough to
know that "c = *p;" is undefined behaviour here, and generate "ud2"
instructions on x86.
 
Yet neither compiler warns about this clearly wrong behaviour despite
-Wall -Wextra.
Ian Collins <ian-news@hotmail.com>: Aug 29 11:35PM +1200

On 29/08/2019 23:24, David Brown wrote:
> instructions on x86.
 
> Yet neither compiler warns about this clearly wrong behaviour despite
> -Wall -Wextra.
 
Use a bigger hammer!
 
$ clang-tidy x.cc
 
1 warning generated.
/tmp/x.cc:11:9: warning: Dereference of null smart pointer 'p' of type
'std::unique_ptr' [clang-analyzer-cplusplus.Move]
c = *p;
^
/tmp/x.cc:9:14: note: Smart pointer 'p' of type 'std::unique_ptr' is
reset to null when moved from
auto q = std::move(p);
^
/tmp/x.cc:11:9: note: Dereference of null smart pointer 'p' of type
'std::unique_ptr'
c = *p;
 
--
Ian.
Bonita Montero <Bonita.Montero@gmail.com>: Aug 29 02:53PM +0200

Rust is nice, but Rust has no exceptions. I wouldn't like to evaluate
this combined error- and return-values after each function-call that
might fail.
Bonita Montero <Bonita.Montero@gmail.com>: Aug 29 02:54PM +0200

> Rust is nowhere near C. Actually, nowhere near C++. It is nice language,
> but not for low level programming. During years they ditched GC and most
> of the things that cripples determinism and performance, ...
 
 
Rust has no GC, but works with counted references.
"Öö Tiib" <ootiib@hot.ee>: Aug 29 06:08AM -0700

On Thursday, 29 August 2019 13:14:29 UTC+3, BGB wrote:
> We add some features to support things like bounds-checked arrays and
> similar;
> We mostly call it done.
 
Rust supports lot of interesting safety features (like RAII, smart pointers,
ownership, generics, move semantics, thread safety).
Adding some safe features at side does not help as history with C++ shows.
Result is bigger language with all the unsafe stuff still there and valid.
OTOH if to cripple the unsafe features a bit then result is some kind of
fourth language that is neither C, C++ nor Rust.
gazelle@shell.xmission.com (Kenny McCormack): Aug 29 01:14PM

In article <qk8hrh$ua3$1@news.albasani.net>,
>Rust is nice, but Rust has no exceptions. I wouldn't like to evaluate
>this combined error- and return-values after each function-call that
>might fail.
 
Why is this posted to CLC? Surely, the comparison is more valid to
C++, given that C++ has things like exceptions and so on. It should have
only been posted to CLC++.
 
(Or, is there a parallel thread going on in CLC++ - that I am not (yet)
aware of?)
 
P.S. Of course there will be a blogs and stuff like this one (the one
referred to in the OP) telling us that Rust is the next big thing and
obviously the thing that is going to be just so absolutely neato keeno that
you'll be unable to imagine how we ever got along with it. This is true
for any new programming language.
 
Look at it this way: If a new programming language came out and there was
no blog post (or whatever) telling us with absolute authority that this is
the absolute greatest thing since, well, ever - that language will have
zero, zip, nada chance of ever being used by anyone.
 
--
Pensacola - the thinking man's drink.
Bonita Montero <Bonita.Montero@gmail.com>: Aug 29 03:38PM +0200

>> this combined error- and return-values after each function-call that
>> might fail.
 
> Why is this posted to CLC? ...
 
Why do you post another Follow-Up there if you consider this as
inadequate.
David Brown <david.brown@hesbynett.no>: Aug 29 08:00PM +0200

On 29/08/2019 13:35, Ian Collins wrote:
 
>> Yet neither compiler warns about this clearly wrong behaviour despite
>> -Wall -Wextra.
 
> Use a bigger hammer!
 
I might well do that. But it won't stop me wanting the feature in the
tools I already use.
 
Keith Thompson <kst-u@mib.org>: Aug 29 01:29PM -0700

> On 29/08/2019 04:36, Melzzzzz wrote:
[...]
>> Having to convert pointer to int and back in order to perform arithmetic
>> is worse that doing it in assembler.
 
> That sounds terrible. (I am not very familiar with Rust.)
 
What's terrible about it? Rust doesn't particularly need pointer
arithmetic; unlike C, it's array indexing isn't defined in terms of
pointers.
 
[...]
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 28 08:46PM -0400

On 8/28/19 10:22 AM, Jens Kallup wrote:
> Hello,
 
> QMap, and other template class "extend" the
> corespond stdC++ std::map<k,v> class.
 
Yes, I know that much about Qt. My point was that, as far as I can tell,
the differences between the Qt classes and the standard classes are not
relevant to the issues I was raising. If I'm wrong about that, please
let me know.
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 28 08:58PM -0400

On 8/28/19 12:00 PM, Öö Tiib wrote:
>> for transmission. Each part is transmitted along with a message ID, a
>> part number, and the total number of parts.
 
> How can receiver realize that all parts have been received?
 
All parts have been received as soon as the number of different parts
that have been collected for a given message ID matches the part count.
 
> Is the message part count known compile time
 
No, it varies with the length of the message provided by the user.
 
> ... and part numbers
> sequential and zero-based?
 
The part numbers are sequential in the order that the parts should occur
in. They are sent out sequentially, but in general, they don't arrive
sequentially. They are 1-based, not 0-based.
 
...
> did change into simpler and so it was cut out from something
> way more overcomplicated. The file change history from repo
> (and commit comments) may illuminate it a bit (if such exist).
 
The entire block of code containing all of the features I described was
added in 2015, and hasn't been changed since. Prior to that, multi-part
messages weren't supported. The commit message didn't provide any
explanation.
 
I was wrong about the person responsible being unavailable - but I'm
having trouble figuring out how to word an inquiry that doesn't make it
sound like I think he wrote something stupid (since, in fact, that is
what I'm thinking).
 
> Results of developers with different skill levels differ by several
> orders of magnitude, but no one notices when that inefficiency
> is in some non-critical part of program.
 
Agreed - the messages are provided by users, and therefore don't arrive
frequently enough for the inefficiency of this approach to be a
significant problem. The inefficiency bothers me, but my boss wouldn't
have let me work on something this low in priority if I weren't
currently stuck between a project I've finished and a project I'm not
allowed to start work on (we're waiting for approval from the client).
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 28 09:05PM -0400

On 8/28/19 2:19 PM, Mike Terry wrote:
> On 28/08/2019 14:30, James Kuyper wrote:
...
>> the corresponding keys to reconstruct the original message.
 
> That sounds so strange, that I wonder if there's a simple explanation:
> the original coder just confused the ordering of the two map parameters?
 
No, that explanation doesn't work. The code includes a comment
indicating that he would have preferred to use QMap<int, QString>, but
failed to clearly explain why he felt that he couldn't use it.
 
 
> Perhaps the intention was to have a map by part number. If multiple
> part numbers were encountered they would be deemed retransmissions and
> it would be OK to just keep the latest one. ...
 
I was rather confused by the fact that every part arrives at least three
times - I suspect that's a bug, but I haven't tracked it down yet.
 
...
> issues coming up would just be worked around. (Like, "hey, seems I need
> to sort by values to get things in the right order?". Yes, seems a bit
> crazy, but maybe the coder was new.
 
That's what I suspect.
 
...
> this. (Put another way, maybe the part map in message map either was,
> or seemed (to the coder) to effectively be a const entry that could only
> be updated through replacement, not modification...)
 
Again, that's pretty much the confusion that I suspect happened.
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 28 09:08PM -0400

On 8/28/19 2:22 PM, Stefan Große Pawig wrote:
> type, including possible conversions. Among these is toMap(), which
> returns a QMap<QString, QVariant>.
 
> Is that map of yours stored in another QVariant?
 
No. The original message map was declared as QMap<QString, QVariant>,
and the QVariant values were filled in with part maps of the type
QMap<QString, int>. I successfully changed the message map to
QMap<QString, QMap<int, QString> > without breaking anything, and that's
because it doesn't interact with any other code that expected QVariants.
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 28 09:11PM -0400

On 8/28/19 3:33 PM, Jorgen Grahn wrote:
> On Wed, 2019-08-28, James Kuyper wrote:
...
 
> That's such an obvious flaw that I'd not trust the rest of that
> programmers choices to make sense. It's simply not a sane way to do
> the trivial task of message reassembly.
 
I agree.
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 28 09:16PM -0400

On 8/28/19 9:08 PM, James Kuyper wrote:
> No. The original message map was declared as QMap<QString, QVariant>,
> and the QVariant values were filled in with part maps of the type
> QMap<QString, int>. I successfully changed the message map to
Correction: QMap<QString, QVariant>.
 
David Brown <david.brown@hesbynett.no>: Aug 29 10:24AM +0200

On 29/08/2019 02:58, James Kuyper wrote:
 
> The part numbers are sequential in the order that the parts should occur
> in. They are sent out sequentially, but in general, they don't arrive
> sequentially. They are 1-based, not 0-based.
 
I would expect that while the parts /could/ arrive out of order, they
will come mostly roughly in-order.
 
Since you know how many parts you will get (once you have received one
part), and you know the part numbers are all 1 .. n, it seems strange to
me that you have a map at all. I'd expect to use a vector,
pre-allocated to the right size when the first part of a new message
arrives. Perhaps you'd want the vector elements to be optional<string>,
or just have empty strings for parts that haven't yet arrived. You
might also want to track a counter of "parts waiting" so that you can
easily see that the last part has arrived, without running through the
vector.
 
> having trouble figuring out how to word an inquiry that doesn't make it
> sound like I think he wrote something stupid (since, in fact, that is
> what I'm thinking).
 
There are other possibilities for this odd data structure - other than
stupidity or inexperience. It could be that the requirements or planned
handling system changed underway - maybe the parts had a different
identification system originally rather than simple integers. It could
be that the code was prototyped in a more dynamic language, such as
Python, or at least one where "variant" types are more common, such as
Visual Basic, and the code then got translated into C++. And of course
it could have been written under inhumane deadlines in the small hours
of the night while overdosed on coffee and cold pizza - a lot of odd
code has been written in such circumstances.
 
 
> have let me work on something this low in priority if I weren't
> currently stuck between a project I've finished and a project I'm not
> allowed to start work on (we're waiting for approval from the client).
 
Inefficiency is often not a huge problem - incorrectness is.
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 29 10:05AM -0400

On 8/29/19 4:24 AM, David Brown wrote:
> On 29/08/2019 02:58, James Kuyper wrote:
...
>> sequentially. They are 1-based, not 0-based.
 
> I would expect that while the parts /could/ arrive out of order, they
> will come mostly roughly in-order.
 
That was my expectation, too. Reality didn't cooperate. During
debugging, I never saw the parts arrive in strict sequential order, and
they often arrived completely jumbled. Sometimes, for small messages,
the final part would be the first one to arrive.
 
That triggered another bug, but I've simplified my explanation of the
code too much to explain why without adding a lot more details. Suffice
it to say that the author apparently expected the final part to always
be the one that arrived last - despite the fact that, if the parts were
guaranteed to arrive in order, he could have simply appended each part
to a string containing the parts that had already been received. That
bug didn't puzzle me as much as the other issues I've mentioned, which
is why I didn't mention it.
 
> might also want to track a counter of "parts waiting" so that you can
> easily see that the last part has arrived, without running through the
> vector.
 
I thought about the vector approach, but with the map approach, the
size() member serves as parts_received, and the total count of parts is
received with every part, so parts_waiting is just the difference. With
the vector approach I'd have to keep track of one additional quantity
(either parts_received, as I thought, or parts_waiting, per your
suggestion). That adds just a little additional complexity, but enough
to discourage me from using that approach.
...
> identification system originally rather than simple integers. It could
> be that the code was prototyped in a more dynamic language, such as
> Python, or at least one where "variant" types are more common, such as
 
That's plausible - some parts of this project are written in python.
 
...
>> currently stuck between a project I've finished and a project I'm not
>> allowed to start work on (we're waiting for approval from the client).
 
> Inefficiency is often not a huge problem - incorrectness is.
 
The code is incorrect, but cases which trigger the bug are extremely
unlikely. With the inefficiency being small, and the incorrectness
unlikely, this is justifiably a low-priority bug. I definitely have more
important things to work on as soon as the work gets approved (I was
investigating one of those more important things when I found this bug).
usenet@stegropa.de (Stefan Große Pawig): Aug 29 08:14PM +0200

[some context restored]
 
>> and the QVariant values were filled in with part maps of the type
>> QMap<QString, int>. I successfully changed the message map to
> Correction: QMap<QString, QVariant>.
 
But then, IIUC, that fits the bill: the QMap<QString, QVariant> for the
parts /was/ stored in another QVariant (namely, as the value type of the
message map).
 
If the code used QVariant::value() to fetch the part map from the message
map, there is no restriction on the type of the part map. The restriction
only arises if the caller used QVariant::toMap().
 
Regardless of what the code originally used, maybe the original author
had just scanned the QVariant interface for anything related to maps,
found only the QMap<QString, QVariant> as baked-in return value and then
assumed that this was the only map type that could be stored in a
QVariant?
 
-Stefan
Jorgen Grahn <grahn+nntp@snipabacken.se>: Aug 29 09:58AM

On Wed, 2019-08-28, Richard wrote:
> approach that many people have tried and failed. It's a really awful
> idea. That suggestion should not be left out in the open
> unchallenged.
 
Yes, that was also worth pointing out, for other readers.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Jorgen Grahn <grahn+nntp@snipabacken.se>: Aug 29 06:09AM

On Wed, 2019-08-28, Ruki wrote:
>> excellent reason.)
 
> Not all os provide spinlocks, and like nginx, they also use their
> own spinlock implementation.
 
I note that that doesn't really answer David's question.
 
Weird that nginx implements spinlocks, when it also advertises itself
as single-threaded. I don't see the use of spinlocks in a situation
where there's only one thread of execution.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Tim Rentsch <tr.17687@z991.linuxsc.com>: Aug 28 06:03PM -0700

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
 
I have now carefully read through all your responses in the
cascade of messages downstream of my message two upthread.
 
> I may address the rest of your posting later, trying to give the
> examples etc. you ask for, because I feel you mean this seriously.
 
I do mean it seriously, and not at all confrontationally. I am
interested to read your further followup (ie, as mentioned above)
if you choose to post one.
 
 
> And I don't think you think you're smarter than everybody else in
> this group just for holding an opinion on UB that nobody else here
> shares.
 
For the most part I don't think about whether I am smarter than
any particular person, let alone everyone in the group, partly
because "smart" is a multi-dimensional quantity, and it's very
rare (if indeed it has ever happened at all) that I find a person
where I think I am smarter along all axes. Even if it were true
that my opinion on a subject were not shared by any other
contributor in the group, that would not affect my sense of what
"smarter" means.
 
 
> I think you're simply convinced that you're right,
 
In my view the word "right" does not apply, because I take both
of our statements as expressing opinions about how the standards
"should" be interpreted. Opinions are never right or wrong, they
just are whatever they are.
 
> that your distinctions are meaningful,
 
I do think the distinctions I have been trying to explain are
meaningful.
 
> and somehow my and others' arguments have failed to move your
> conviction.
 
I think an essential first step is missing. For my views to
change as a result of what you say (or vice versa), I must first
understand what you mean and why you think what you do (similarly
vice versa). Right now I think we are not understanding each
other. Key example: the term "undefined behavior". Even though
we both use the term "undefined behavior", I think what you mean
by the term is not the same as what I mean by it. If that is so
then obviously it gets in the way of us communicating. Normally
in discussions like this one, my efforts are directed at trying
to convey what I think and why, and not to try to convince the
other participant(s) to change their minds.
 
 
> Which I think means we're not good enough at presenting our
> view. Not, that we're wrong. ;-)
 
Again, I don't think either of our views is right or wrong. I
agree though that explaining what it is you think should be given
more emphasis than trying to convince me that you're right.
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: