Friday, January 10, 2020

Digest for comp.lang.c++@googlegroups.com - 18 updates in 6 topics

Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 08:10AM -0800


> On 31.12.2019 19:46, Bonita Montero wrote:
 
[...]
 
>> This would be disturbing if you would have the function in the
>> code for a later purpose.
 
> So you are checking in untested code.
 
On the contrary, such unused functions are completely tested:
any function that is never called cannot possibly misbehave. The
warning message saying the function is unused is the success
indicator for testing the function in question. It is only
functions that are called that might contain program errors.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 08:29AM -0800


> (The word "may" is a bit ambiguous, and it could be argued that an
> implementation isn't required to support constants of type int128_t
> even if it's an extended integer type.)
 
Not really convincingly. The end of that paragrah says
 
If an integer constant cannot be represented by any type in
its list and has no extended integer type, then the integer
constant has no type.
 
I don't see any sensible way of reading those sentences together
and concluding that using an extended integer type is allowed to
be optional.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 08:46AM -0800


> So the footnote effectively asserts that its conclusions are implied
> by normative rules, though it's not clear that there's any normative
> text in the C standard that supports the claim in this footnote.
 
In my reading of the C standard, there is normative text that
establishes the assertion in the footnote.
 
> If the normative requirements in C++ are sufficiently similar to
> those in C, one could argue that the assertion in that footnote is
> as valid for C++ as for C.
 
The C++ standard clearly does not admit the same reasoning as the
C standard in this regard, because the definedness of accessing
union members is tied (in C++) to their lifetimes, and the
lifetimes are not the same in C++ as they are in C. In C++, the
"UB-ness" of accessing a different union member can be established
constructively (ie, it is not just a question of a definition
being omitted).
 
> (My own conclusion is that the lack of supporting normative text is a
> flaw in the C standard. It should make a clear normative statement
> about the behavior of type punning using union members.)
 
There is normative text that implies what the footnote says. That
isn't as obvious as some people might like, so it would be good if
the behavior were described more directly, for clarity. But the
behavior is described more directly: it is described in this very
footnote.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jan 10 09:51AM -0800

> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
>> text in the C standard that supports the claim in this footnote.
 
> In my reading of the C standard, there is normative text that
> establishes the assertion in the footnote.
 
Do you have some reason for not telling us where that normative
text is? I know this is comp.lang.c++, but I suggest that the
presence of such text in the C standard, and its absence in the C++
standard, is relevant to C++.
 
> "UB-ness" of accessing a different union member can be established
> constructively (ie, it is not just a question of a definition
> being omitted).
 
Please consider telling us *how* it can be established constructively
rather than just being vague.
 
[...]
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
[Note updated email address]
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 02:19PM -0800

Robert Wessel <robertwessel2@yahoo.com> writes:
 
[...]
 
> VLAs present considerable implementation difficulties on some
> small systems,
 
Do you mean small in the sense of limited resources? Or small in
the sense of not having a full hosted library? What problems are
there in these small systems that don't come up in larger systems?
 
> and present a number of issues with regards to stack growth on all
> implementations
 
VLAs may present some issues with regard to stack growth, but they
don't have to. The Standard admits implemenations that put VLAs
somewhere other than on the stack, eg, allocated with malloc().
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 02:51PM -0800

> route). "Minimal" or "trivial" library, probably.
 
> Or you implement creal and cimag as macros (implementation dependent,
> but trivial, in most cases).
 
These functions can be done completely portably for any implementation
that has _Complex. Here are the 'double' versions:
 
double
creal( _Complex double z ){
return (union { _Complex double z; double dd[2]; }){ z }.dd[0];
}
 
double
cimag( _Complex double z ){
return (union { _Complex double z; double dd[2]; }){ z }.dd[1];
}
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 02:59PM -0800

> text is? I know this is comp.lang.c++, but I suggest that the
> presence of such text in the C standard, and its absence in the C++
> standard, is relevant to C++.
 
I didn't have time for a longer posting. Also I don't think it's
relevant for C++ because there is additional text in the C++
standard that explicitly makes such accesses be undefined behavior.
 
>> being omitted).
 
> Please consider telling us *how* it can be established constructively
> rather than just being vague.
 
My comments were consciously incomplete, but I don't think it's
fair to call them vague, just incomplete. In any case I will try
to post a more complete explanation sometime soon, in comp.lang.c.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 01:53PM -0800


> Generally the O(n**2) sorts are considered usable up a few tens of
> items. And use insertion sort, not bubble sort (simpler algorithm,
> twice as fast on average).
 
The simplest bubble sort is simpler than the simplest insertion
sort.
 
The most complete bubble sort is simpler than the most complete
insertion sort.
 
It is only if we compare a somewhat less complete rendition of
insertion sort to a somewhat more complete rendition of bubble
sort that "insertion sort" may be called simpler.
 
I agree that insertion sort is a better choice than bubble sort
in almost all cases, but saying insertion sort is simpler than
bubble sort is an apples-and-oranges comparison.
Robert Wessel <robertwessel2@yahoo.com>: Jan 10 04:45PM -0600

On Fri, 10 Jan 2020 13:53:52 -0800, Tim Rentsch
 
>I agree that insertion sort is a better choice than bubble sort
>in almost all cases, but saying insertion sort is simpler than
>bubble sort is an apples-and-oranges comparison.
 
 
For common definitions of what bubble and insertion sorts are,
insertion sorts are simpler.
 
Standard versions in C:
 
void InsertionSort(int a[], int length)
{
int i, j, temp;
 
for(i = 1; i < length; i++)
{
temp = a[i];
for (j = i - 1; j >= 0 && a[j] > temp; j--)
a[j + 1] = a[j];
a[j] = temp;
}
}
 
void BubbleSort(int a[], int length)
{
int i, j, temp;

for (i = 0; i < length; i++)
{
for (j = 0; j < length - i - 1; j++)
{
if (a[j + 1] < a[j])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
 
There's not a lot of difference there (basically all the same lines of
code, except that the "if" in the bubble sort has been folded into
insertion sort's inner loop termination test). But there's little to
add to the insertion sort, while the bubble sort is usually enhanced
by adding a check to stop if no swapping has been done in a pass,
adding more code (and if you don't, the usual claim that bubble sort
works well on already sorted files is false). If you do the swap test
in bubble sort you can simplify the outer loop, but a fair cost in
performance for unsorted inputs.
 
Enhancement to both are possible (if somewhat pointless), but often
result in what's usually considered a different sort. Using a binary
search to determine the insertion point, or working the bubble sort
from both ends result in binary insertion and cocktail shaker sorts,
for example.
Mister2U@honorific.org: Jan 10 12:28PM

On Thu, 9 Jan 2020 12:59:29 -0800 (PST)
>But if it may refuse to work until all floats are received then
>I probably would copy half but would throw after timeout
>destroying all the received floats and not processing anyway.
 
These sort of problems are why any genuine network programmer always includes
the expected packet size in a stream packet (usually at the beginning) instead
of doing something stupid like sending raw XML or json on its own where
constant parsing is required to see if the end of the data has been reached yet
and may get it wrong if the formatting is bad and continue waiting for data
beyond the end. For UDP where data send in a single write is returned in a
single read that approach is fine, not so for TCP. Sadly a new generation of
programmers has yet to figure this out.
David Brown <david.brown@hesbynett.no>: Jan 10 02:02PM +0100

>> I probably would copy half but would throw after timeout
>> destroying all the received floats and not processing anyway.
 
> These sort of problems are why any genuine network programmer always includes
 
This is a matter of protocol design, not programming. Any "genuine
network programmer" writes code to handle the protocol specified -
whether it includes a packet size or not.
 
Protocols where the length of the telegram is given either explicitly in
a header, or implied from the protocol type, make reception simpler.
But they can involve more work when generating the data. There is a
trade-off here, and it is not as simple as saying one method is always
best. (Having said that, I prefer to give the length explicitly when
designing protocols.)
 
> beyond the end. For UDP where data send in a single write is returned in a
> single read that approach is fine, not so for TCP. Sadly a new generation of
> programmers has yet to figure this out.
 
Some protocols on top of TCP/IP or UDP, such as MQTT, have length fields
in the telegrams.
 
For JSON, a very simple solution is to use newline-delimited JSON - you
send the JSON string, then a linefeed character. It's easy to see when
you have the whole string, because you have found a character 10, and
can then start parsing.
 
I think it would be nice to see more use of SCTP, which combines the
benefits of TCP/IP and UDP - letting you get the "datagram" feature of
UDP while also getting the guarantees and fragmentation control of
TCP/IP. But it is not well supported in common routers (or Windows),
making it a lot harder to establish it for common use.
Mister2U@honorific.org: Jan 10 04:21PM

On Fri, 10 Jan 2020 14:02:38 +0100
 
>This is a matter of protocol design, not programming. Any "genuine
>network programmer" writes code to handle the protocol specified -
>whether it includes a packet size or not.
 
Well yes, but I was talking about when designing one.
 
>send the JSON string, then a linefeed character. It's easy to see when
>you have the whole string, because you have found a character 10, and
>can then start parsing.
 
That'll work fine - until you have ascii 10 inside a quoted string which is
entirely plausible. The same problem exists if doing simple curly bracket
counting. Its a non trivial problem and shouldn't be something the network
layer has to worry about.
 
>I think it would be nice to see more use of SCTP, which combines the
 
Unfortunately SCTP is de facto dead. It was a good attempt but didn't get the
traction.
David Brown <david.brown@hesbynett.no>: Jan 10 07:18PM +0100

> entirely plausible. The same problem exists if doing simple curly bracket
> counting. Its a non trivial problem and shouldn't be something the network
> layer has to worry about.
 
No, it is not plausible - you can't have ASCII 10 in the JSON string.
It must be escaped as "\n".
 
 
>> I think it would be nice to see more use of SCTP, which combines the
 
> Unfortunately SCTP is de facto dead. It was a good attempt but didn't get the
> traction.
 
Exactly.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 07:44AM -0800

Jorgen Grahn <grahn+nntp@snipabacken.se> writes:
 
[...]
 
> I always assumed parsing meant reading any kind of data, deciding if
> it matches the parser's language, and if it does, offering the
> "pieces" in a helpful way to the next step of processing.
 
This description is consistent with my own understanding and also
with the various definitions and other online resources I
consulted.
 
> E.g. yacc is a parser generator, but in my mind so is scanf().
 
I wouldn't say scanf() is a parser generator, because it doesn't
generate a parser but rather goes ahead and does (some) parsing.
 
Perhaps more significantly, usually scanf() is used to parse not
an entire language but only some part of an input, with other
calls to scanf() parsing other parts of the input (and hence
other parts of the language being accepted). To me scanf() is
closer to being a lexer than a parser. However these are minor
distinctions; it's fair to say that a scanf() call parses a
line (or some other part) of an input.
 
> (And as background: I know for sure I was taught in computer science
> that "language" is anything with a syntax and (I suppose) semantics.
> It doesn't have to be Turing-complete or anything.)
 
In formal Computer Science, a language is any set of strings over
a finite alphabet. In most cases we are concerned only with those
languages that can be recognized by a computer program, and so
necessarily have a finite (and well-defined) "grammar". I put the
word "grammar" in quotes only because computer programs are more
varied than what is generally meant by the word grammar.
 
By themselves languages are just sets of strings, and do not have
any associated semantics. However it is certainly right that
a language needn't be large or "complete" in any sense. The set
of strings { "cat", "dog" } qualifies as a language in formal
language theory.
 
 
> [...] I tend to do things which fit in Unix pipelines.
 
(Comment about English language usage only.) In English, this
sentence is better written using "that" in place of "which". The
reason is the word "that" is restrictive, whereas the word "which"
is non-restrictive. That should be enough so you can read a more
full description somewheres on the web. (Or if not ask and I will
try to track down a good reference.)
 
(Note: my comment is meant only to be helpful, not corrective. My
friends for whom English is not their first language tell me it's
helpful for them to hear remarks like this, so their English can
be better. That's all I'm trying to do here.)
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 06:48AM -0800


> On 04/01/2020 04:04, Frederick Gotham wrote:
 
>> auto main(void) -> int
 
> What kind of an abomination is this?
 
As abominations go, it's one of the best.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jan 10 07:06AM -0800


>>> What kind of an abomination is this?
 
>> It fails to compile on older C++ compilers, before C++11
 
> It should fail to compile with compilers that enforce good taste.
 
So, not on any currently conforming C++ compiler, you mean?
boltar@nowhere.org: Jan 10 12:18PM

On Thu, 9 Jan 2020 12:42:23 -0800 (PST)
 
>The std::tuple is variadic template and so its elements are
>enumerated during its generation. For such stinky myclass it
>is most trivial to make those manually.
 
If quite capable of writing a class method called get() though I wouldn't use
such a ridiculously complex method that you have, I wanted to how to use
the standard library get() for my classes as per tuple and variant. It can be
done with a tuple cast overload method in the class but unfortunately when
using get() it requires an explicit cast in the call. eg:
 
auto val = get<0>((tuple<string,int,int>)(myobj));
 
Which works but is ugly.
guinness.tony@gmail.com: Jan 10 07:04AM -0800

> :
> };
 
> cout << get<0>(obj); <- How would I make this return string s for example?
 
I have presumed (as Öö Tiib also did) that you actually want the mapping
 
get<0>(obj) <=> obj.b
get<1>(obj) <=> obj.i
get<2>(obj) <=> obj.s
 
The following function templates did the trick for me. The second one also
facilitates lvalue access (just as the std::get<>() function templates do),
so you can perform indexed-member assignments, e.g.
 
get<2>(obj) = "foo";
 
---- 8< ----
 
#include <tuple>
 
template<std::size_t I> constexpr auto const& get(myclass const& obj)
{ return std::get<I>(std::tie(obj.b, obj.i, obj.s)); }
 
template<std::size_t I> constexpr auto& get(myclass& obj)
{ return std::get<I>(std::tie(obj.b, obj.i, obj.s)); }
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: