Friday, September 21, 2018

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

Bart <bc@freeuk.com>: Sep 21 05:28PM +0100

On 21/09/2018 16:17, Rick C. Hodgin wrote:
>> possibly have, other than their favourite language doesn't have such
>> constructs?
 
> I can think of three off the top of my head:
 
Objections?
 
>     if (xt = yt = treal) ...
 
In C-style that would need to be == not ==
 
 
>     if (c in {'A'..'Z', '0'..'9', 'a'..'z'}) ...
 
> And simplified:
 
>     if (c in {a_z, 0_9, a_z}) ...
 
(I'm introducing simple forms of Range and Set constructs, from my
dynamic language where they are first-class types. (Both originally from
Pascal; the Set is a bit-set not the complicated container type you find
these days.)
 
But they will not be types of their own.
 
The Set construct is used to build 32-, 64- or 128-bit integer values.
That limits it to 128 elements (compared with a billion in the other
language), but that is enough to deal with ASCII codes.
 
const alpha = ['A'..'Z', 'a'..'z'] # value is 128-bit int
const digits = ['0'..'9']
const ident = alpha ior digits ior ['_'] # ior means "|"
 
if c in alpha ...
if n in [1,2,4,8] ...
if c not in ident ...
 
The Range construct is used for array bounds, as switch-case ranges (gcc
has these as 'A'...'Z'), to build Sets, and for tests like this as I've
already shown:
 
if a in 0..255 ...
 
Full treatment of such things I don't think belong in a C-class language
but cut-down versions as above I believe are useful, and fairly easy to
implement. They directly translate to simple integer and bit wise
operations.)
 
--
bart
jameskuyper@alumni.caltech.edu: Sep 21 09:43AM -0700

On Friday, September 21, 2018 at 10:19:36 AM UTC-4, bitrex wrote:
 
> I've been writing C/C++ off and on since ALL THE WAY BACK in the late
> 1990s and I can't say it ever occurred to me to write a test like if ( a
> < b < c ) ...
 
Well, of course not - (a < b) < c is a pretty unusual thing to want to calculate. In principle, it could happen, and the amount of C code that
has been written is so great that it's almost certainly the case that
someone, somewhere, has deliberately written a < b < c, knowing that it
would be interpreted as (a < b) < c, because that's what they actually
wanted to calculate. But it's certainly extremely rare.
 
> ... I'd probably just write (a < b && b < c) by force of habit.
 
And the fact that you'd want to write that implies that you didn't want
to calculate (a < b) < c.
 
My objection to this proposal is not based upon the huge quantities of
existing code that would be broken by it - such breakage would be
extremely rare.
My objection is based upon the fact that it is inconsistent with the
design of the rest of the language. a < b is a perfectly good expression
in it's own right which returns a value of type int. It's behavior in
the proposed a < b < c can NOT be describe in terms of the second '<'
operating on the value returned by a < b, which makes it very different
from any other type of C expression.
 
The only other expression types that surround an operand with tokens are
?: and various expression types that use [], (), or {} to surround the
operand. Since none of the members of those pairs can appear on their
own, you never get a case where part of the entire expression looks
like an expression in it's own right, but isn't treated as one. There's
no possibility, in any of the following expressions, that the part
extending from the beginning up to b will be interpretable as an
expression in it's own right. The same is true of the part starting at
'b' and extending to the right:
 
a ? b : c
a[b]
a(b)
(a){b, c}
(a)b
_Generic(a, int:b, float:c)
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Sep 21 12:43PM -0400

On 9/21/2018 12:28 PM, Bart wrote:
>>> have, other than their favourite language doesn't have such constructs?
 
>> I can think of three off the top of my head:
 
> Objections?
 
I was being silly. I simply added parenthesis around yours.
 
>>      if (xt = yt = treal) ...
 
> In C-style that would need to be == not ==
 
I just copied what you wrote. I didn't even pay that much
attention to what it was because I was just adding the paren-
thesis..
 
 
> (I'm introducing simple forms of Range and Set constructs, from my dynamic
> language where they are first-class types. (Both originally from Pascal; the
> Set is a bit-set not the complicated container type you find these days.)
 
I remember those. I've considered how to implement them in
CAlive and came up with [|definition|] casks that allow for
[|min|value||], [|max|value||], [|range|min,max||].
 
> But they will not be types of their own.
 
In CAlive, they are not enforced, but they signal an exception
for <|range|func()||> to be added wherever needed on any oper-
ation.
 
 
>   if c in alpha ...
>   if n in [1,2,4,8] ...
>   if c not in ident ...
 
Interesting.
 
 
> Full treatment of such things I don't think belong in a C-class language but
> cut-down versions as above I believe are useful, and fairly easy to
> implement. They directly translate to simple integer and bit wise operations.)
 
I really admire your unique and creative approach toward language
extensions. I enjoy reading them in the various posts.
 
--
Rick C. Hodgin
bitrex <user@example.net>: Sep 21 12:49PM -0400

On 09/21/2018 10:57 AM, Bart wrote:
 
> (What would the alternative to nested for-loops be I wonder? Or switch
> statements? Or multi-way comparisons, whatever you mean by that. Are we
> still allowed 'if' or is that also bad design?
 
Lots of tasks that require nested loops in C can be accomplished in C++
using the standard algorithms operating on containers, you'd want to use
those whenever possible.
 
<http://www.cplusplus.com/reference/algorithm/>
 
> I'd be interested in seeing what your code looks like when most control
> flow statement are eliminated. I'd imagine it would have either have a
> functional look, or perhaps it's just full of C++-ese.)
 
Writing "C++ese" is what all that stuff is there for! golly!
 
 
> Here's one actual example of mine (syntax not from C or C++, so "="
> means "=="), which is a 4-way compare:
 
>  if hd.hsample[2] = hd.vsample[2] = hd.hsample[3] = hd.vsample[3] ...
 
it's an error-prone statement (all copy-paste statements are.) e.g. if
you accidentally write:
 
if hd.hsample[2] = hd.vsample[2] = hd.hsample[3] = hd.hsample[3]
 
can someone not familiar see what's different in 5 seconds? if you don't
notice it yourself and the incorrect statement returns a valid result
that compiles OK ya ded and then you (or someone!) tear ya hair out for
four hours trying to find it. Even "Big name" codebases are filled with
bugs like that.
 
bitrex <user@example.net>: Sep 21 01:01PM -0400

> the proposed a < b < c can NOT be describe in terms of the second '<'
> operating on the value returned by a < b, which makes it very different
> from any other type of C expression.
 
The two-way comparison operators return bool in C++, yeah?
 
<https://en.cppreference.com/w/cpp/language/operator_comparison>
 
(looks like this topic was cross-posted so maybe some ambiguity about
what lang we're talking about here.)
 
in C++ this works fine: if (a < ( b < c ? b : false))
 
jameskuyper@alumni.caltech.edu: Sep 21 10:25AM -0700

On Friday, September 21, 2018 at 1:01:48 PM UTC-4, bitrex wrote:
> On 09/21/2018 12:43 PM, jameskuyper@alumni.caltech.edu wrote:
...
> > operating on the value returned by a < b, which makes it very different
> > from any other type of C expression.
 
> The two-way comparison operators return bool in C++, yeah?
 
True - but the type of the value it returns isn't relevant to the point
I was raising. All that matters is that it does return a value, and that
the proposed new meaning for a < b < c cannot be interpreted as the
second operator operating on the value returned by the first one.
C++ has added a lot of new syntax in the latest release, that I'm not
yet familiar with - the rest of my message might have to be re-written
to cover C++ as well, but I believe that the basic point I'm trying to
make is equally valid for either language.
 
 
> (looks like this topic was cross-posted so maybe some ambiguity about
> what lang we're talking about here.)
 
> in C++ this works fine: if (a < ( b < c ? b : false))
 
It works, in the sense that it has well-defined behavior so long as a,
b, and c have appropriate types. I'm not sure there's any easy way to
describe what it does. It's certainly not equivalent to either the
current meaning of a < b < c, nor the proposed new meaning for that
expression. Why do you bring it up?
Bart <bc@freeuk.com>: Sep 21 06:25PM +0100

On 21/09/2018 17:49, bitrex wrote:
> you accidentally write:
 
> if hd.hsample[2] = hd.vsample[2] = hd.hsample[3] = hd.hsample[3]
 
> can someone not familiar see what's different in 5 seconds?
 
Writing:
 
if hd.hsample[2]=hd.vsample[2] and hd.vsample[2]=hd.hsample[3] and
hd.hsample[3]=hd.vsample[3] ...
 
would be even more error-prone! It means writing 6 terms instead of 4.
 
And it is necessary for the terms either side of the 'and's to match,
which introduces another source of errors when the same term has to be
repeated: if updating one instance, you must update the other too.
 
(Note that your modified version compares the same term with itself,
which is the sort of thing a compiler might warn about.)
 
 
if you don't
> that compiles OK ya ded and then you (or someone!) tear ya hair out for
> four hours trying to find it. Even "Big name" codebases are filled with
> bugs like that.
 
 
Yes. But as I said, using this construct *reduces* the scope for such
errors.
 
--
bart
Keith Thompson <kst-u@mib.org>: Sep 21 10:46AM -0700

> zero-neg-label, zero-zero-label, zero-pos-label,
> pos-neg-label, pos-zero-label, pos-pos-label
 
> (The more things change, the more they stay the same.)
 
C++20 is adding a "three-way comparison operator", <=>, inspired by
Perl's "spaceship operator". It compares two values and yields less,
equal, or greater (of type std::strong_ordering), with some added
complications for floating-point operands. Using it with a switch
statement would be similar to what you (sarcastically, I presume)
propose.
 
See also
https://github.com/Keith-S-Thompson/fizzbuzz-c/blob/master/fizzbuzz093.c
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Bart <bc@freeuk.com>: Sep 21 06:54PM +0100

On 21/09/2018 17:43, jameskuyper@alumni.caltech.edu wrote:
 
[I might be killfilled by this poster, but decided to post anyway.]
 
> the proposed a < b < c can NOT be describe in terms of the second '<'
> operating on the value returned by a < b, which makes it very different
> from any other type of C expression.
 
If the syntax is converted to s-expressions, then:
 
A < B < C
 
using the normal semantics could be expressed like this:
 
(LT (LT A B) C)
 
The outer LT operates on the result of the inner LT as you said.
 
My crude implementation performs a transformation so that you end up with:
 
(AND (LT A B) (LT B C))
 
Which works fine, except there's a flaw because B occurs twice here, and
only once in the original source, which is a no-no.
 
A workaround could create a temporary and copy B into that. But I think
this requires a special construct within the language, denoted by this:
 
(CHAINCMP
(A LT)
(B LT)
C)
 
This will always have two or more of those pairs (otherwise it's a
regular compare), ending with the single tail expression.
 
Then middle terms only appear once, and it's easy to generate the most
suitable code.
 
(That this would be incompatible with how both C and C++ work now is a
significant detail that shouldn't be overlooked.
 
Both those languages also have a small problem with the relative
precedences of EQ/NE, compared with LT/LE/GE/GT. For this proposal, they
would really need to be the same.)
 
--
bart
bitrex <user@example.net>: Sep 21 03:10PM -0400

On 09/21/2018 01:25 PM, Bart wrote:
 
>  if hd.hsample[2]=hd.vsample[2] and hd.vsample[2]=hd.hsample[3] and
>     hd.hsample[3]=hd.vsample[3] ...
 
> would be even more error-prone! It means writing 6 terms instead of 4.
 
I wouldn't write that either! You would use range-based iterators and
the std library functions that operate on the iterators returned by
containers like std::equal, std::lexicographical_compare, etc.
 
 
Siri Cruise <chine.bleu@yahoo.com>: Sep 21 12:12PM -0700

In article <lnd0t6agkz.fsf@kst-u.example.com>, Keith Thompson <kst-u@mib.org>
wrote:
 
> complications for floating-point operands. Using it with a switch
> statement would be similar to what you (sarcastically, I presume)
> propose.
 
Doesn't everyone want to program in 1966 Fortran?
 
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
An almond doesn't lactate. This post / \
Yet another supercilious snowflake for justice. insults Islam. Mohammed
bitrex <user@example.net>: Sep 21 03:14PM -0400

On 09/21/2018 01:25 PM, Bart wrote:
>> with bugs like that.
 
> Yes. But as I said, using this construct *reduces* the scope for such
> errors.
 
in situation where you have say a vector and want to compare elements
prefer to use proxy objects like iterators for comparisons and not like
my_vector[0], my_vector[1], etc.
 
unless you actually have to destructively alter the contents of the
container don't touch 'em directly, don't do nothin' with 'em!
"Öö Tiib" <ootiib@hot.ee>: Sep 21 12:34PM -0700

On Friday, 21 September 2018 22:12:46 UTC+3, Siri Cruise wrote:
> > statement would be similar to what you (sarcastically, I presume)
> > propose.
 
> Doesn't everyone want to program in 1966 Fortran?
 
The C++ (like always) actually tries to top up the complications
invented in other languages. When the operands of spaceship are
floating point types then the "three-way comparison" will evaluate
to one of four values of std::partial_ordering. ;)
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Sep 21 03:53PM -0400

On 9/21/2018 3:12 PM, Siri Cruise wrote:
> Doesn't everyone want to program in 1966 Fortran?
 
People often make fun of Fortran, but it's still a first-tier
compiler receiving modern optimizations provided for by Intel
(along with their C++ compiler).
 
https://software.intel.com/en-us/intel-compilers
 
I regularly hear speakers on compute-related videos report
that their scientists say there isn't a better language to
express the formulas they use for calculation than in Fortran.
 
I've never used it personally. I play to support it with
RDC though at some point.
 
--
Rick C. Hodgin
Bart <bc@freeuk.com>: Sep 21 09:53PM +0100

On 21/09/2018 20:10, bitrex wrote:
 
> I wouldn't write that either! You would use range-based iterators and
> the std library functions that operate on the iterators returned by
> containers like std::equal, std::lexicographical_compare, etc.
 
So what would you write? In any syntax.
 
Forget the "hd." parts, you have:
 
int hsample[4]; // sampling rate per component
int hsample[4];
 
When number of components is 3 (eg. RGB), then you want to test that
hsample[1], vsample[1], hsample[2], vsample[2] (using 0-based index) all
have the same value before proceeding.
 
Is there a simpler and more robust way than using (in C syntax and with
chained compare ops):
 
if (hsample[1] == vsample[1] == hsample[2] == vsample[2])
 
?
 
 
 
--
bart
bitrex <user@example.net>: Sep 21 04:58PM -0400

On 09/21/2018 04:53 PM, Bart wrote:
 
> Forget the "hd." parts, you have:
 
>    int hsample[4];        // sampling rate per component
>    int hsample[4];
 
?????? see what I mean I don't trust me either!
 
Bart <bc@freeuk.com>: Sep 21 10:28PM +0100

On 21/09/2018 21:58, bitrex wrote:
 
>>     int hsample[4];        // sampling rate per component
>>     int hsample[4];
 
> ?????? see what I mean I don't trust me either!
 
This is a typo that would be picked up, so is of no consequence.
(Obviously one of those will be vsample.)
 
>> Is there a simpler and more robust way than using (in C syntax and
>> with chained compare ops):
 
>>     if (hsample[1] == vsample[1] == hsample[2] == vsample[2])
 
I'm still interested in the magical solution that is simple and less
error-prone than this.
 
--
bart
"Öö Tiib" <ootiib@hot.ee>: Sep 21 03:00PM -0700

On Saturday, 22 September 2018 00:28:53 UTC+3, Bart wrote:
 
> >>     if (hsample[1] == vsample[1] == hsample[2] == vsample[2])
 
> I'm still interested in the magical solution that is simple and less
> error-prone than this.
 
No need to make new programming languages for that, just write two
one-liners in C++11 and done. Nothing magical.
Example that will work with operands of any types between what
operator == that returns bool exists.
 
 
template<typename T, typename U>
bool allEqual(T&& t, U&& u)
{
return (t == u);
}
 
template<typename T, typename U, typename... Ts>
bool allEqual(T&& t, U&& u, Ts&&... args)
{
return (t == u) && allEqual(u, std::forward<Ts>(args)...);
}
 
// done, now you have allEqual(a,b,c,d,...)
// usage:
#include <iostream>

int main()
{
int hsample[4] = {42, 42, 42, 42};
int vsample[4] = {0, 42, 42, 666};
if (allEqual(hsample[1], vsample[1], hsample[2], vsample[2]))
{
std::cout << "yes\n";
}
}
Paavo Helde <myfirstname@osa.pri.ee>: Sep 21 07:08PM +0300

On 21.09.2018 18:26, Stefan Ram wrote:
> sentence of this post:
 
> reinterpret_cast< ::std::uintptr_t >pointer
 
> static_cast< ::std::uintptr_t >pointer
 
As the second one does not compile, the choice seems easy to me ;-)
 
It does not compile because despite its name uintptr_t is not a pointer
type.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Sep 21 09:43PM +0200

On 21.09.2018 17:26, Stefan Ram wrote:
> [snip]
> reinterpret_cast< ::std::uintptr_t >pointer
> static_cast< ::std::uintptr_t >pointer
 
Both are syntax errors.
 
When that's fixed the `static_cast` is invalid.
 
* * *
 
There was once an issue with the standard's wording for
`reinterpret_cast`, so that Andrei and Herb recommended
 
static_cast<Ptr_to_A>( static_cast<void*>( ptr_to_B ) )
 
instead of
 
reinterpret_cast<Ptr_to_A>( ptr_to_B ) )
 
However, as I recall, but this is a vague memory, the wording was fixed
in C++11 so that now the two are also formally equivalent, so no longer
is there even a formal reason to use the more convoluted construct.
 
 
Cheers!
 
- Alf
Jorgen Grahn <grahn+nntp@snipabacken.se>: Sep 21 04:26PM

On Thu, 2018-09-20, Bart wrote:
 
>> Python is different because there's a word "pyton" for the snakes, and
>> because Monty Python got local pronounciation back in the 70s.
 
> That doesn't stop Americans pronouncing it as PyTHON.
 
Note that I never said it should. (In fact, I said the opposite.)
 
As far as I'm concerned, this thread is only for entertainment
purposes.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Sep 21 02:33AM +0200

On 21.09.2018 01:48, Tim Rentsch wrote:
 
> This assertion is fairly common, but it isn't right. Running out
> of stack space is not undefined behavior as the C standard defines
> the term. A lot of people find this very counter-intuitive;
 
That's because it's the wrong standard. For C++ it's the C++ standard
that rules. Except where it defers to the C standard.
 
 
> whether those conditions exist (in the physical machine) or not.
> Hence we know what the abstract machine is supposed to do, and
> therefore the behavior is defined.
 
Nope.
 
You're confusing the C formal term with the formal term in the C++
standard, which does correspond closely to the common speech meaning.
 
 
C++17 $3.27 [defns.undefined]
<quote>
undefined behavior
behavior for which this International Standard imposes no requirements
[Note: Undefined behavior may be expected when this International
Standard omits any explicit definition of behavior or when a program
uses an erroneous construct or erroneous data. Permissible undefined
behavior ranges from ignoring the situation completely with
unpredictable results, to behaving during translation or program
execution in a documented manner characteristic of the environment (with
or without the issuance of a diagnostic message), to terminating a
translation or execution (with the issuance of a diagnostic message).
Many erroneous program constructs do not engender undefined behavior;
they are required to be diagnosed. Evaluation of a constant expression
never exhibits behavior explicitly specified as undefined (8.20). —end
note ]
</quote>
 
The note in the brackets is non-normative text, but explains things.
 
In contrast to C++, the C11 definition limits C "undefined behavior" to
"behavior, upon use of a nonportable or erroneous program construct or
of erroneous data, for which this International Standard imposes no
requirements", which is indeed counter-intuitive and more than a little
bit impractical.
 
 
> then the program has no undefined behavior as the
> Standard uses the term, and running out of stack space
> doesn't change that.
 
Point 3 here blatantly contradicts the above quoted definition of
"undefined behavior" in C++17, which is the same definition as in
earlier C++ standards, back to C++98.
 
 
> with the C++ standard, so please take that into account. I would
> appreciate any pointers for passages in the C++ standard that
> might be at odds with what is written above.)
 
Oh. Well. When you try to argue against someone's C++ terminology by
referring to a standard for /another language/, you're just too far out.
 
Not that it isn't interesting. I think that the silly definitions the
standardization committees sometimes end up with is interesting from a
psychological point of view. I think it's about establishing a kind of
group speech, using special meanings only known to (psychology term)
in-group members, thus helping to identify and exclude others.
 
 
Cheers!,
 
- Alf
"Öö Tiib" <ootiib@hot.ee>: Sep 20 06:13PM -0700

On Friday, 21 September 2018 02:49:16 UTC+3, Tim Rentsch wrote:
> question, but it is also a meaningless question. The Standard
> specifies the behavior of /programs/; it does not specify the
> behavior of /situations/.
 
Standard does describe situations. Those are situations that cause
malloc to return null pointer or errno to be set ENOMEM or ENOSPC
and the like. What else these are?
 
> then the program has no undefined behavior as the
> Standard uses the term, and running out of stack space
> doesn't change that.
 
Anything that is not defined by any passage of standard *is*
undefined behavior in C++. That may be different in C.
Is it in C that because standard does not state that automatic
storage has limits and what happens when the limits are exhausted
then the automatic storage is unlimited in C?
 
> limits of physical hardware are exceeded or not/. Such things
> do not exist in the abstract machine, and so the given semantic
> descriptions continue to apply.
 
In C++ it is that since standard does not define what happens when some
local variable breaks automatic storage limits then what actually happens
is undefined behavior exactly because standard did not define it.
Paavo Helde <myfirstname@osa.pri.ee>: Sep 21 06:52PM +0300

On 21.09.2018 2:48, Tim Rentsch wrote:
 
>> [..scenarios that might overflow the program stack..]
 
> A common reaction at this point might ask "if the behavior is
> defined, then where is it defined?"
 
For stack overflow, the behavior might be defined by the implementation.
For example, with MSVC++ on x86 there is a way to make stack overflow a
recoverable error, though it's tricky to get right and has a good chance
to make the whole program slower. Those not faint in the heart should
start with the _resetstkoflw() documentation.
 
Note that if the behavior were defined by the C++ standard, MSVC++ could
not implement their own behavior (at least not legally).
ram@zedat.fu-berlin.de (Stefan Ram): Sep 21 03:26PM

I wonder whether there is any difference (in value/behavior)
between the following two expressions, and which one should
be used to convert a pointer to an unsigned integer type in
the sense of
 
N2176 (C, not C++!), 7.20.1.4p1
 
|The following type designates an unsigned integer type with
|the property that any valid pointer to void can be converted
|to this type, then converted back to pointer to void, and the
|result will compare equal to the original pointer:
|
|uintptr_t
 
. Here are the two expressions referred to by the first
sentence of this post:
 
reinterpret_cast< ::std::uintptr_t >pointer
 
static_cast< ::std::uintptr_t >pointer
 
.
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: