Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Semantics of comma operator

221 views
Skip to first unread message

Geoff

unread,
Jan 9, 2018, 12:29:39 PM1/9/18
to
Clang/LLVM is now warning about suspicious use of comma operator and
the following statement causes the warning:

while ((c = fgetc (in)), c != EOF)

My instinct tells me to write this as:

while ((c = fgetc (in)) && c != EOF)

but the advice from Xcode is to "cast the expression to void to
silence this warning". I prefer to dispose of questionable idiomatic
usage over hiding it. I am not the original author of this code.

What is your opinion?

James R. Kuyper

unread,
Jan 9, 2018, 12:50:29 PM1/9/18
to
On 01/09/2018 12:29 PM, Geoff wrote:
> Clang/LLVM is now warning about suspicious use of comma operator and
> the following statement causes the warning:
>
> while ((c = fgetc (in)), c != EOF)
>
> My instinct tells me to write this as:
>
> while ((c = fgetc (in)) && c != EOF)

This has different behavior than the original code if the character read
in is '\0'. Unless you actually want different behavior in that case,
it's probably a bad idea.

> but the advice from Xcode is to "cast the expression to void to
> silence this warning". I prefer to dispose of questionable idiomatic
> usage over hiding it. ...

You have good instincts; if there's a legitimate problem, the cast won't
fix it, it will merely hide it.

> ... I am not the original author of this code.
>
> What is your opinion?
>
while( (c = fgetc(in)) != EOF )

Alf P. Steinbach

unread,
Jan 9, 2018, 12:58:37 PM1/9/18
to
On 1/9/2018 6:29 PM, Geoff wrote:
> Clang/LLVM is now warning about suspicious use of comma operator and
> the following statement causes the warning:
>
> while ((c = fgetc (in)), c != EOF)
>
> My instinct tells me to write this as:
>
> while ((c = fgetc (in)) && c != EOF)
>

For binary file that would be technically wrong. For text file it would
mislead the reader, indicating a possibility (reading a null value) that
can then never occur. And so you really don't want to do that.


> but the advice from Xcode is to "cast the expression to void to
> silence this warning".

It's insane.

But what's insanity to a reasoning informed mind, can be just wholesome
common thinking to an associative uninformed mind. I would guess that
whoever designed that warning belongs to the latter class. And so it's
not necessarily an insane person, but merely a very incompetent one.


> I prefer to dispose of questionable idiomatic
> usage over hiding it. I am not the original author of this code.
>
> What is your opinion?


The first loop is idiomatic and correct.


Cheers & hth.,

- Alf

Chris Vine

unread,
Jan 9, 2018, 1:07:09 PM1/9/18
to
The second version will fail if '\0' is a valid character in this
context: it frequently is, as end-of-string. I should stick to whatever
your intention is. I suspect there must be a compiler flag to silence
this warning.

Incidentally if you want to post these kinds of messages, you should
post the error message.

Chris

Scott Lurndal

unread,
Jan 9, 2018, 1:34:20 PM1/9/18
to
r...@zedat.fu-berlin.de (Stefan Ram) writes:
>Geoff <ge...@invalid.invalid> writes:
>>Clang/LLVM is now warning about suspicious use of comma operator and
>>the following statement causes the warning:
>>while ((c = fgetc (in)), c != EOF)
>
> It's hard to add anything after James and Alf, but one thing
> that comes to mind might be an inline function:
>
>#define E(condition) __builtin_expect((condition)!=0, 1)
>#define whilee( expr ) while( E( expr ))
>
>whilee( stream_to_char( in, &c ))

So you can then use

whilee(coyote) {}

Most of our projects adopt the linux 'likely' and 'unlikely'
definitions.

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

while (likely(condition)) {
}

Richard

unread,
Jan 9, 2018, 2:04:15 PM1/9/18
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<p32vs1$298$1...@dont-email.me> thusly:

>On 1/9/2018 6:29 PM, Geoff wrote:
>> Clang/LLVM is now warning about suspicious use of comma operator and
>> the following statement causes the warning:
>>
>> while ((c = fgetc (in)), c != EOF)
>>
>> My instinct tells me to write this as:
>>
>> while ((c = fgetc (in)) && c != EOF)
>
>The first loop is idiomatic and correct.

I think Clang/LLVM warning because the order of operations was
undefined for user-overloaded comma operator before C++17. However,
for situations where you are using the built-in comma operator (as in
this one), the order of operations is well defined. So it seems that
this is a spurious warning from Clang.

<http://en.cppreference.com/w/cpp/language/operator_other#Built-in_comma_operator>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Alf P. Steinbach

unread,
Jan 9, 2018, 2:10:37 PM1/9/18
to
On 1/9/2018 8:04 PM, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
> <p32vs1$298$1...@dont-email.me> thusly:
>
>> On 1/9/2018 6:29 PM, Geoff wrote:
>>> Clang/LLVM is now warning about suspicious use of comma operator and
>>> the following statement causes the warning:
>>>
>>> while ((c = fgetc (in)), c != EOF)
>>>
>>> My instinct tells me to write this as:
>>>
>>> while ((c = fgetc (in)) && c != EOF)
>>
>> The first loop is idiomatic and correct.
>
> I think Clang/LLVM warning because the order of operations was
> undefined for user-overloaded comma operator before C++17.

The warning's advice to cast to `void` would not help with ordering,
would it?


> However,
> for situations where you are using the built-in comma operator (as in
> this one), the order of operations is well defined. So it seems that
> this is a spurious warning from Clang.
>
> <http://en.cppreference.com/w/cpp/language/operator_other#Built-in_comma_operator>

The interesting thing about the comma operator, to me, is that it
doesn't quite fit into a strict operator precedence.

It's interesting to me because I've forgotten the examples of that... :)


Cheers!,

- Alf

Geoff

unread,
Jan 9, 2018, 5:01:28 PM1/9/18
to
The warning message is "Possible misuse of comma operator here" and
the offer to fix is issued in the Xcode IDE. The option being set is
"CLANG_WARN_COMMA" per the project configuration help. Setting it to
NO is also an option. I'm not sure what the default is supposed to be
and it appears it's not documented by Apple yet for Xcode.

This is in fact a C file, not C++ and I posted in the wrong group,
sorry about that.

Geoff

unread,
Jan 9, 2018, 5:09:14 PM1/9/18
to
Thanks. I like this better than maintaining the idiomatic use.

Geoff

unread,
Jan 9, 2018, 5:27:31 PM1/9/18
to
On Tue, 9 Jan 2018 18:58:23 +0100, "Alf P. Steinbach"
<alf.p.stein...@gmail.com> wrote:

>On 1/9/2018 6:29 PM, Geoff wrote:
>> Clang/LLVM is now warning about suspicious use of comma operator and
>> the following statement causes the warning:
>>
>> while ((c = fgetc (in)), c != EOF)
>>
>> My instinct tells me to write this as:
>>
>> while ((c = fgetc (in)) && c != EOF)
>>
>
>For binary file that would be technically wrong. For text file it would
>mislead the reader, indicating a possibility (reading a null value) that
>can then never occur. And so you really don't want to do that.
>

It's a text file. The usage appears twice, counting the file
characters first, allocating memory, then rewind and load the file
into the allocated buffer.

>
>> but the advice from Xcode is to "cast the expression to void to
>> silence this warning".
>
>It's insane.
>
>But what's insanity to a reasoning informed mind, can be just wholesome
>common thinking to an associative uninformed mind. I would guess that
>whoever designed that warning belongs to the latter class. And so it's
>not necessarily an insane person, but merely a very incompetent one.
>

>
>> I prefer to dispose of questionable idiomatic
>> usage over hiding it. I am not the original author of this code.
>>
>> What is your opinion?
>
>
>The first loop is idiomatic and correct.
>
>

Indeed it is. That's why I was surprised when the warning showed up in
previously valid code. It seems Apple decided to set the default in
Xcode to warn about suspicious comma usage. I created a new "hello
world" project from the GUI and it defaults to CLANG_WARN_COMMA = YES.
This is in the "all languages" section of the Xcode project settings
so they have chosen to apply it universally.

red floyd

unread,
Jan 9, 2018, 7:06:46 PM1/9/18
to
I always thought that *WAS* idiomatic use. Going back to K&R.

Juha Nieminen

unread,
Jan 10, 2018, 2:39:44 AM1/10/18
to
Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> The first loop is idiomatic and correct.

Why would anybody write

while ((c = fgetc (in)), c != EOF)

when they could write

while ((c = fgetc (in)) != EOF)

asetof...@gmail.com

unread,
Jan 10, 2018, 4:45:11 AM1/10/18
to
"idiomatic use" is not
while ((c = fgetc (in)) && c != EOF)

It is
while((c=fgetc(in))!= EOF)...

Alf P. Steinbach

unread,
Jan 10, 2018, 5:21:19 AM1/10/18
to
The way you write it is by far more common; I've never seen the comma
operator separation of side effect and checking before this thread.

But they do the same, as opposed to the OP's variation it's just
notation this, and some might regard the first as more clear.

I think maybe such person might write `s[i] = f(); ++i;`, while you and
probably also I would write `s[i++] = f();`. Still I have written the
former, because of fear of enticing reader into the world of side-effect
expressions. It depends on who one imagines one communicates to I guess.


Cheers!,

- Alf






James R. Kuyper

unread,
Jan 10, 2018, 7:13:02 AM1/10/18
to
To the best of my knowledge, this IS the idiomatic use. Using the comma
operator, which forces you to repeat the 'c', is not idiomatic.

Richard

unread,
Jan 10, 2018, 4:03:00 PM1/10/18
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<p34pea$pdg$1...@dont-email.me> thusly:

>On 1/10/2018 8:39 AM, Juha Nieminen wrote:
>> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>>> The first loop is idiomatic and correct.
>>
>> Why would anybody write
>>
>> while ((c = fgetc (in)), c != EOF)
>>
>> when they could write
>>
>> while ((c = fgetc (in)) != EOF)

Nit: I object to the space after fgetc because it disrupts visual flow.

Vir Campestris

unread,
Jan 11, 2018, 4:28:43 PM1/11/18
to
On 09/01/2018 22:27, Geoff wrote:
> It's a text file. The usage appears twice, counting the file
> characters first, allocating memory, then rewind and load the file
> into the allocated buffer.

Seek to end. ftell. Seek to start. Allocate buffer. Read.

You don't need to read the file twice.

Andy

James R. Kuyper

unread,
Jan 11, 2018, 5:01:56 PM1/11/18
to
On 01/11/2018 04:28 PM, Vir Campestris wrote:
> On 09/01/2018 22:27, Geoff wrote:
>> It's a text file. The usage appears twice, counting the file
>> characters first, allocating memory, then rewind and load the file
>> into the allocated buffer.
>
> Seek to end. ...

The C++ standard library function fseek() is defined only by
cross-referencing the C standard, and the corresponding iostream
facilities have their behavior defined in terms of fseek().

C 2011, 7.21.9.2p3: "A binary stream need not meaningfully support fseek
calls with a whence value of SEEK_END".

Note that this is NOT 'implementation-defined" behavior, so an
implementation is under no obligation to document whether it
meaningfully supports SEEK_END.

Richard

unread,
Jan 11, 2018, 6:00:20 PM1/11/18
to
[Please do not mail me a copy of your followup]

Vir Campestris <vir.cam...@invalid.invalid> spake the secret code
<p38ktm$9om$1...@dont-email.me> thusly:

>On 09/01/2018 22:27, Geoff wrote:
>> It's a text file. The usage appears twice, counting the file
>> characters first, allocating memory, then rewind and load the file
>> into the allocated buffer.
>
>Seek to end. ftell. Seek to start. Allocate buffer. Read.

Isn't it surprising how many people don't know this trick? This
method is portable, but a non-portable alternative is to use a
filesystem API to obtain the file size (stat in posix, GetFileSize{,Ex}
in Windows).

In C++17, you can call std::filesystem::file_size as well.

Alf P. Steinbach

unread,
Jan 11, 2018, 6:27:00 PM1/11/18
to
On 1/11/2018 11:01 PM, James R. Kuyper wrote:
> On 01/11/2018 04:28 PM, Vir Campestris wrote:
>> On 09/01/2018 22:27, Geoff wrote:
>>> It's a text file. The usage appears twice, counting the file
>>> characters first, allocating memory, then rewind and load the file
>>> into the allocated buffer.
>>
>> Seek to end. ...
>
> The C++ standard library function fseek() is defined only by
> cross-referencing the C standard, and the corresponding iostream
> facilities have their behavior defined in terms of fseek().
>
> C 2011, 7.21.9.2p3: "A binary stream need not meaningfully support fseek
> calls with a whence value of SEEK_END".

Shouldn't that be “needs”?


> Note that this is NOT 'implementation-defined" behavior, so an
> implementation is under no obligation to document whether it
> meaningfully supports SEEK_END.

It would be interesting to know the (OS or storage) systems where
`SEEK_END` can't be relied on in practice.

I can't quite grok what it's about. For a pipe or tape drive or
non-seekable stream, or generally where the request can't be satisfied,
`fseek` will just return non-zero. So what's that “meaningfully” about?


Cheers!,

- Alf (baffled)

Richard

unread,
Jan 11, 2018, 6:52:50 PM1/11/18
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<p38rro$p2h$1...@dont-email.me> thusly:

>I can't quite grok what it's about. For a pipe or tape drive or
>non-seekable stream, or generally where the request can't be satisfied,
>`fseek` will just return non-zero. So what's that “meaningfully” about?

I interpret the language to imply that fseek would succeed by
returning 0, but that the consequences of doing so wouldn't be
meaningful. In other words it says "yeah, I did it" but there was no
observable change in reality.

For instance, the following program:

#include <stdio.h>

int main()
{
FILE *f = fopen("/dev/random", "rb");
printf("%ld pos on open\n", ftell(f));
fseek(f, 0, SEEK_END);
printf("%ld pos on seek\n", ftell(f));
fclose(f);
}

gives the following output:

0 pos on open
0 pos on seek

Chris Vine

unread,
Jan 11, 2018, 7:42:58 PM1/11/18
to
On Fri, 12 Jan 2018 00:26:47 +0100
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
> > C 2011, 7.21.9.2p3: "A binary stream need not meaningfully support
> > fseek calls with a whence value of SEEK_END".
>
> Shouldn't that be “needs”?

It's a subjunctive.

Geoff

unread,
Jan 12, 2018, 12:23:11 AM1/12/18
to
As stated elsewhere in this topic, the file being sized is a text
file.

The fseek/ftell method doesn't yield identical results with text files
on Windows compared to Linux or OSX due to the brain-dead decision to
use <CR><LF> in Windows disk files and this code is intended to be
portable. Windows correctly translates the line endings to <LF> in
memory.

The text file is small, currently 125 bytes in memory and 129 bytes on
a Windows platform and will never exceed 1000 bytes. Over-allocation
would not be harmful in this case but I didn't see much benefit in
re-writing something that has been working for decades. The surprise
was the sudden appearance of warnings about the comma usage in this
particular source file. This turned out to be due to an Xcode update
that turns on that warning by default. As I stated, I didn't write
this code, I only maintain it.

What's interesting is this is either copy-pasted cargo-cult or the
original author knew about this behavior and wanted identical counts
across platforms. Someone "sophisticated" enough to use the comma
operator syntax would presumably know about fseek/ftell and I have
used it elsewhere in my other projects.

Manfred

unread,
Jan 12, 2018, 8:11:54 AM1/12/18
to
Are you sure?

James R. Kuyper

unread,
Jan 12, 2018, 9:54:32 AM1/12/18
to
On 01/11/2018 04:28 PM, Vir Campestris wrote:
Correction: I should have noticed that Geoff was referring to a text
file. The situation for text streams is worse than that for binary
streams. The following clause "the new position, measured in characters
from the beginning of the file, is obtained by adding offset to the
position specified by whence." (7.21.9.2p3), applies applies only "For a
binary stream". There is NO corresponding definition for the behavior of
fseek() on a text stream in the section describing fseek(), so it might
seem that the behavior is undefined "by the omission of any explicit
definition of behavior" (4p6).
However, the description of ftell() does say "For a text stream, its
file position indicator contains unspecified information, usable by the
fseek function for returning the file position indicator for the
stream to its position at the time of the ftell call;". Using values not
returned by ftell() does have undefined behavior.

James R. Kuyper

unread,
Jan 12, 2018, 10:12:25 AM1/12/18
to
There are operating systems that don't keep track of the end of the file
at the byte level, but only at the block level, padding the file with
null characters to the end of the block. This is permitted by 7.21.2p3:
"A binary stream is an ordered sequence of characters that can
transparently record internal data. Data read in from a binary stream
shall compare equal to the data that were earlier written out to that
stream, under the same implementation. Such a stream may, however, have
an implementation-defined number of null characters appended to the end
of the stream."

The result of using SEEK_END might take you to the end of the last block
of the file, rather than to the end of what was written to the file.

Another example would be certain special readable files under unix, such
as /dev/zero. You can read as many bytes as you want from that file, but
seeking to the end of that file will still leave you at position 0 in
the file.


On Friday, June 25, 2004 at 5:31:10 PM UTC-4, P.J. Plauger wrote:
> "Kevin D. Quitt" <KQuitt...@IEEIncUNMUNG.com> wrote in message
> news:u24pd09gbn5j1ago3...@4ax.com...
>
>> On 25 Jun 2004 11:38:22 GMT, Dan...@cern.ch (Dan Pop) wrote:
>> >Let's say that you open a binary file in write
>> >mode and write 10 bytes to it. You close it, reopen it in read mode and
>> >start reading. After reading, say, 512 bytes, you get an EOF instead of
>> >a byte value. What is the size of your binary file: 10 or 512 bytes
>> >and why?
>>
>> It's hard for me to imagine why an OS would allow me to read more than the
>> 10 bytes I wrote when writing and reading as a stream. That's not to say
>> there isn't one, of course.
>
> And in 1983, when the standardization of C began, it was hard to find
> an OS that *did* let you read just the bytes you wrote to it. Even
> Unix, that paragon of simplicity and elegance, has block-special devices
> that violate this rule. It is a mark of the influence of Unix that you
> can make a statement like this today.

See <https://groups.google.com/d/msg/comp.std.c/WGxu-woWcMc/pt5_1j8uIC0J>:

Manfred

unread,
Jan 12, 2018, 10:42:49 AM1/12/18
to
An alternative and more robust solution is to read the file sequentially
and dynamically (re)allocate the buffer on the fly, until an end of file
condition is encountered.
This works whenever the file can be just read (not fseek'd/ftell'd), at
the potential cost of higher memory fragmentation.
This may be of some relevance in some scenarios, but IME the
cost/benefit evaluation often favors this second alternative.

Another alternative could be stat(), on platforms where it is available
(it's part of POSIX, but not of ISO C).

James R. Kuyper

unread,
Jan 12, 2018, 11:45:06 AM1/12/18
to
For some reason, this is all I see when I view your message:

On 01/12/2018 11:23 AM, Stefan Ram wrote:

Chris Vine

unread,
Jan 12, 2018, 1:33:15 PM1/12/18
to
God forbid that I be not sure.

James Kuyper

unread,
Jan 13, 2018, 1:43:12 PM1/13/18
to
On 01/12/2018 11:49 AM, Stefan Ram wrote:
> "James R. Kuyper" <james...@verizon.net> writes:
>> For some reason, this is all I see when I view your message:
>
> It seems that you are replying to some message,
> but your post does not have a reference header.

I would imagine that's because, as received by my newsreader, the
message didn't have enough information to construct a reference header.
When I did "View Source" on the message, I only got an empty screen -
which makes me wonder how Thunderbird constructed the line it displays
on the screen for that message, which contains the Subject, From, and
Date. Obviously, something is badly messed up.

The message I was responding to was posted by you, with this subject,
quite recently, and apparently (judging by it's position in the display)
as a response to a message of mine. If you know of any such message,
could you either re-post it, or at least e-mail me a copy?

James Kuyper

unread,
Jan 13, 2018, 1:49:38 PM1/13/18
to
On 01/12/2018 11:23 AM, Stefan Ram wrote:
> "James R. Kuyper" <james...@verizon.net> writes:
>> The result of using SEEK_END might take you to the end of the last block
>> of the file, rather than to the end of what was written to the file.
>
> Sometimes, a function to count the number of possible calls
> to getc might help. I have written - but not tested - such
...

Keep in mind that, on the systems I was referring to, such an approach
might result in reading the padding null characters at the end of the
file, and including them in the file size.

Bonita Montero

unread,
Jan 13, 2018, 2:06:44 PM1/13/18
to
> while ((c = fgetc (in)), c != EOF)
I use it often similary.
But in this case you can omit the parenthesis around
"(c = fgetc (in))" becuase the comma-operator has the
lowest precedence.
I also use the comma-operator for small blocks when
there isn'T no any control-structures and I have a
low line-count in the "block".

Keith Thompson

unread,
Jan 13, 2018, 4:30:04 PM1/13/18
to
Geoff <ge...@invalid.invalid> writes:
[...]
> It is in a C context. I managed to post the question in the wrong
> group somehow. It is a text file opened with "rt" flags in the fopen
> call.

"rt" as the second argument to fopen() is non-standard (neither ISO C
nor POSIX describes it). Apparently in some implementations it's
treated as equivalent to "r".

--
Keith Thompson (The_Other_Keith) ks...@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"

Alf P. Steinbach

unread,
Jan 13, 2018, 8:09:21 PM1/13/18
to
On 1/13/2018 8:47 PM, Stefan Ram wrote:
> James Kuyper <james...@verizon.net> writes:
>> On 01/12/2018 11:49 AM, Stefan Ram wrote:
>>> "James R. Kuyper" <james...@verizon.net> writes:
>>>> For some reason, this is all I see when I view your message:
>>> It seems that you are replying to some message,
>>> but your post does not have a reference header.
>> The message I was responding to was posted by you, with this subject,
>> quite recently, and apparently (judging by it's position in the display)
>> as a response to a message of mine. If you know of any such message,
>> could you either re-post it, or at least e-mail me a copy?
>
> Thanks for your interest in my messages! Of course, I was
> looking for the reference header so as to get to know
> /which/ message it was that you were asking for. But from
> the context it seems that this should have been the message
>
> <getc-count-2...@ram.dialup.fu-berlin.de>

Here is a standard link that would be clickable if our tools still worked:

<url: news://getc-count-2...@ram.dialup.fu-berlin.de>

I tried it with both Thunderbird and Sylpheed and they don't do what a
news client should do. But it's still better than a non-standard format
that gets erroneously interpreted as a mail address.

With a bit more work one can find a GMail archive URL, e.g. as discussed
here,

<url: https://productforums.google.com/forum/#!topic/Apps/UCY9_ek0h3o>

Essentially, in Google Groups search for "messageid: MY_MESSAGE_ID"

For the above message that kind of search yielded exactly 0 hits.

However, a ditto search for ...

>
> that you then replied to in your message
>
> <p3dkbh$ek8$1...@dont-email.me>

yielded

<url:
https://groups.google.com/forum/#!msg/comp.lang.c++/MWSZ4KlLu7I/sb8xwHFjAwAJ>

which headers show that the message id given earlier was correct.

It seems that Google Groups don't archive your posts in comp.lang.c++.

Perhaps you're posting with "don't archive this please" header?

Checking...

Yes, you have imposed your own silly scheme that nobody knows about:

> X-No-Archive: Yes
> Archive: no
> X-No-Archive-Readme: "X-No-Archive" is only set, because this prevents some
> services to mirror the article via the web (HTTP). But Stefan Ram
> hereby allows to keep this article within a Usenet archive server
> with only NNTP access without any time limitation.



Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Jan 14, 2018, 12:15:14 AM1/14/18
to
On 1/14/2018 2:31 AM, Stefan Ram wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>> <getc-count-2...@ram.dialup.fu-berlin.de>
>> I tried it with both Thunderbird and Sylpheed and they don't do what a
>> news client should do. But it's still better than a non-standard format
>> that gets erroneously interpreted as a mail address.
>
> msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
> is defined in RFC 5322 which specifies an Internet
> standards track protocol. On the Internet one cannot
> get more standard than this.

Let me quote what you snipped:

> you have imposed your own silly scheme that nobody knows about:
>
>> X-No-Archive: Yes
>> Archive: no
>> X-No-Archive-Readme: "X-No-Archive" is only set, because this prevents some
>> services to mirror the article via the web (HTTP). But Stefan Ram
>> hereby allows to keep this article within a Usenet archive server
>> with only NNTP access without any time limitation.
>
>

And no, a message id is not an URL.

Still, maybe the URL I tried was incorrect, e.g. the "//", but much
better than what you posted that modern clients interpret as an e-mail
address.

David Brown

unread,
Jan 14, 2018, 6:33:15 AM1/14/18
to
This is possibly a Thunderbird bug. I have seen this happening on rare
occasions - I think mainly in connection with network problems. My
theory on what happens is that Thunderbird has collected the start of
the post (subject, reference, poster) but has not bothered to collect
the body of the post until you start to read it. However, if there is a
problem in the network, server, etc., when you try to read it, it is
possible for Thunderbird to mark the post as downloaded and read, even
though it did not actually get it.

James Kuyper

unread,
Jan 14, 2018, 6:53:04 AM1/14/18
to
This isn't the first time it's happened to me, and your guess seems
consistent with the symptoms I've seen. It is the first time that it's
affected a message that seems to have been a response to one of my
messages, where that response was unavailable on Google Groups (due to
Stefan's No-Archive headers).

Geoff

unread,
Jan 14, 2018, 1:06:12 PM1/14/18
to
... and from this point forward the topic was hijacked.

Thank you very much.

Vir Campestris

unread,
Jan 14, 2018, 4:21:16 PM1/14/18
to
On 13/01/2018 19:06, Bonita Montero wrote:
> But in this case you can omit the parenthesis around
> "(c = fgetc (in))" becuase the comma-operator has the
> lowest precedence.

I just looked. There are 17 levels of operator precedence.

Please consider that future readers of your code may not have memorised
them all.

Andy

Tim Rentsch

unread,
Jan 14, 2018, 7:11:07 PM1/14/18
to
"James R. Kuyper" <james...@verizon.net> writes:

Both are idiomatic. You might say one is more well-known than
the other, or more commonly used. But both are idiomatic.

David Brown

unread,
Jan 14, 2018, 7:13:47 PM1/14/18
to
On 14/01/18 22:48, Stefan Ram wrote:
> Vir Campestris <vir.cam...@invalid.invalid> writes:
>> Please consider that future readers of your code may not have memorised
>> them all.
>
> When someone is learning Italian, he is supposed to learn
> several irregular verb forms by heart. One single verb has
> dozens of forms, and there are dozens of irregular verbs.
> Not to mention literally thousands of nouns he has to learn.
>
> A programmer should have mental capabilities way beyond
> those of mere Italian learners. How can it be possible
> that a programmer can't memorize 20 levels of precedence,
> and shall not even be bothered to look them up? Even
> ordinary doctors learn hundreds and hundreds of medical
> terms.
>
> Disclaimer: I don't know all precedence levels by heart,
> I look them up if need be. This is what I can
> write from my memory, but I'm just guessing, I'm not sure:
>
<snip mistakes>
>
> I'm sure I have made some mistakes and omissions above.
> As I said, I look up the precedence when I need to know it.
>

It is simply /crazy/ to write code that where you have a reasonable
expectation that average programmers will have to look up a reference
manual to interpret it correctly.

Some types of code are naturally difficult - some code in C++ is
downright mystical even for the world's leading experts. You can expect
that it will be difficult for most people to understand - and most
people will use references when trying to interpret it.

But most people will /not/ use references when reading or writing code
with operators. They will, like you, guess. And they will mostly get
it correct. Sometimes, however, they will get it wrong, especially when
using less common operators and combinations. "1<<4 + 5" is 512, not
21. "(1 << 4) + 5" leaves no room for confusion.

It is irresponsible to write code that it harder to understand than
necessary, for something as trivial as saving a couple of characters.
(If there are so many parenthesis that they become confusing, the
expression should be split up.) It is downright scary to hear this
attitude from someone who claims to teach C and C++ classes. I really
hope your students have other sources of good programming practice than
their teacher.

Tim Rentsch

unread,
Jan 14, 2018, 7:41:34 PM1/14/18
to
Juha Nieminen <nos...@thanks.invalid> writes:

> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>
>> The first loop is idiomatic and correct.
>
> Why would anybody write
>
> while ((c = fgetc (in)), c != EOF)
>
> when they could write
>
> while ((c = fgetc (in)) != EOF)

If asked to decide between writing

while (suitable(c=getchar())) ...

and writing

while (c=getchar(),suitable(c)) ...

(with the understanding that these two lines are the only choices
available), normally I would choose the second way, because I
think it's better not to bury the assignment inside the function
call argument list. Similarly, if asked to decide between writing

if ((p=malloc(amount))) ...

and writing

if (p=malloc(amount),p) ...

normally I would choose the second way, because I think it makes
it more plainly evident that the = is meant as an assignment (and
also because I think putting in extra parentheses to suppress a
warning that some compilers give is kind of dumb). Similarly
again, if asked to decide between writing

while ((c=getchar())!=EOF && c!='\n') ...

and writing

while (c=getchar(), c!=EOF && c!='\n') ...

normally I would choose the second way, to emphasize the symmetry
of the condition being tested.

Returning to the original question, for reasons of consistency
normally I would write the while() condition using a comma
operator, rather than testing against the value of the assignment
expression. Also I think the imperativeness of the while()
condition should stand out - it's not a pure expression but has a
state-changing function call (and also assignment), and I think
that distinction is worth bringing to the reader's attention.

Tim Rentsch

unread,
Jan 14, 2018, 7:48:32 PM1/14/18
to
Geoff <ge...@invalid.invalid> writes:

> On Tue, 9 Jan 2018 18:58:23 +0100, "Alf P. Steinbach"
> <alf.p.stein...@gmail.com> wrote:
>
>> On 1/9/2018 6:29 PM, Geoff wrote:
>>
>>> Clang/LLVM is now warning about suspicious use of comma operator and
>>> the following statement causes the warning:
>>>
>>> while ((c = fgetc (in)), c != EOF)
>>>
>>> My instinct tells me to write this as:
>>>
>>> while ((c = fgetc (in)) && c != EOF)
>>
>> For binary file that would be technically wrong. For text file it would
>> mislead the reader, indicating a possibility (reading a null value) that
>> can then never occur. And so you really don't want to do that.
>
> It's a text file. The usage appears twice, counting the file
> characters first, allocating memory, then rewind and load the file
> into the allocated buffer.
>
>>> but the advice from Xcode is to "cast the expression to void to
>>> silence this warning".
>>
>> It's insane.
>>
>> But what's insanity to a reasoning informed mind, can be just wholesome
>> common thinking to an associative uninformed mind. I would guess that
>> whoever designed that warning belongs to the latter class. And so it's
>> not necessarily an insane person, but merely a very incompetent one.
>>
>
>>
>>> I prefer to dispose of questionable idiomatic
>>> usage over hiding it. I am not the original author of this code.
>>>
>>> What is your opinion?
>>
>> The first loop is idiomatic and correct.
>
> Indeed it is. That's why I was surprised when the warning showed up in
> previously valid code. It seems Apple decided to set the default in
> Xcode to warn about suspicious comma usage. I created a new "hello
> world" project from the GUI and it defaults to CLANG_WARN_COMMA = YES.
> This is in the "all languages" section of the Xcode project settings
> so they have chosen to apply it universally.

I had to hunt to find the clang option that would turn on this
warning, which normally is off. Considering what I've learned
about it so far, I recommend turning it off and leaving it off.
I'm surprised that Xcode saw fit to enable it by default, but
then Xcode often makes choices that are IMO ill-advised.

Geoff

unread,
Jan 14, 2018, 11:11:54 PM1/14/18
to
Done and done. I opened an older project that had not been opened in
the IDE and the latest iteration of Xcode popped up a dialog to update
project settings and indeed, "Suspicious Commas" was changed from no
to yes. I expect I'll have to be on the lookout for this from now on
unless the Apple geeks change it again.

Geoff

unread,
Jan 14, 2018, 11:22:40 PM1/14/18
to
I have a feeling Apple will be undoing this change in Xcode since it
also flags constructs like:

src++, dest++;

Ian Collins

unread,
Jan 14, 2018, 11:27:44 PM1/14/18
to
On 01/15/2018 05:22 PM, Geoff wrote:
>
> I have a feeling Apple will be undoing this change in Xcode since it
> also flags constructs like:
>
> src++, dest++;

It does spot some nasty bugs as well. We leave it on by default in our
builds. I'm guessing the boost folks do as well, there was a condition
flagged in the last but one release that has been fixed.

--
Ian.

James R. Kuyper

unread,
Jan 15, 2018, 8:12:01 AM1/15/18
to
On 01/14/2018 04:54 PM, Stefan Ram wrote:
[Re: precendence levels in C]
> Ok, now correcting, using notes:
>
> r...@zedat.fu-berlin.de (Stefan Ram) writes:

To the extent that the rules of the C language can be described in terms
of operator precedence (which is a considerable extent), the precedence
levels correspond to the sub-sections of section 6.5.

6.5.1: Primary expressions:
identifier
'constant'
"string-literal"
>> (x)
_Generic()

6.5.1: Postfix expressions.
>> x[...]
>> x....

Your notation is confusing, because the member selection operator blends
in with your ellipses. I assume you meant what I would describe using

x.member

>> x->...
>> x(...)
>
> Here, a new level should have started by writing
> an empty line.

No, this is not a different level.

>> x++
>> x++
>
> Was intended to read "x--".

(type_name){initializer, list}
(type_name){initializer, list,}

6.5.3: Unary operators
>> --x
>> ++x
>> -x
>> +x
>> !x
>> ~x
>
> forgot: &x, *x, sizeof x

_Alignof(type_name)

6.5.4: Cast operators
> forgot: (cast)x


6.5.5: Multiplicative operators
>> x*y
>> x/y
>
> forgot: x%y

6.5.6: Additive operators
>> x+y
>> x-x

6.5.7: Bitwise shift operators
>> x<<y
>> x>>y

6.5.8: Relational operators
> Oops, a major omission: Totally forgot
> x<y, x>y, x<=y and x>=y here.

6.5.9: Equality operators
> x==y x!=y

6.5.10: Bitwise AND operator
>> x&y

6.5.12: Bitwise exclusive OR operator
>> x|y

6.5.11: Bitwise inclusive OR operator
>> x^y ???
> ^ is higher than |, I thought about that
> possibility, but was not sure.

6.5.13: Logical AND operator
>> x&&y

6.5.14: Logical OR operator
>> x||y

|| has lower precedence than &&.

6.5.15: Conditional operator
>> x?y:z (does not exactly fit)

To be precise, the way in which it fails to fit is that any expression
between the '?' and the ':' is evaluated in it's entirety, and used as
the second operand of the operator, so in that regard, ?: has lower
precedence than any other operator. However, with regard to its first
and third operands, it behaves exactly as if it had precedence between
that of || and assignment expressions.

6.5.16: assignment operators
>> x = y
>> x += y and so on

6.5.17: Comma operator
>> x,y


Manfred

unread,
Jan 15, 2018, 10:08:44 AM1/15/18
to
On 1/15/2018 1:13 AM, David Brown wrote:
> On 14/01/18 22:48, Stefan Ram wrote:
>> Vir Campestris <vir.cam...@invalid.invalid> writes:
>>> Please consider that future readers of your code may not have memorised
>>> them all.
>>
<snip>
>>
>>    Disclaimer: I don't know all precedence levels by heart,
>>    I look them up if need be. This is what I can
>>    write from my memory, but I'm just guessing, I'm not sure:
>>
> <snip mistakes>
>>
>>    I'm sure I have made some mistakes and omissions above.
>>    As I said, I look up the precedence when I need to know it.
>>
>
> It is simply /crazy/ to write code that where you have a reasonable
> expectation that average programmers will have to look up a reference
> manual to interpret it correctly.
>
I believe this is a bit hard as it is stated. I agree this is not good
practice, but I wouldn't categorize as hard as crazy.
Bad practice is not the same as crazy, I think. Besides, you wrote
yourself that there are cases where code cannot be written to be easily
readable.

> Some types of code are naturally difficult - some code in C++ is
> downright mystical even for the world's leading experts.  You can expect
> that it will be difficult for most people to understand - and most
> people will use references when trying to interpret it.
>
> But most people will /not/ use references when reading or writing code
> with operators.  They will, like you, guess.  And they will mostly get
> it correct.  Sometimes, however, they will get it wrong, especially when
> using less common operators and combinations.  "1<<4 + 5" is 512, not
> 21.  "(1 << 4) + 5" leaves no room for confusion.
>
> It is irresponsible to write code that it harder to understand than
> necessary, for something as trivial as saving a couple of characters.
> (If there are so many parenthesis that they become confusing, the
> expression should be split up.)
I tend to agree with the baseline, although I think that expression
splitting serves more that readability only.

  It is downright scary to hear this
> attitude from someone who claims to teach C and C++ classes.  I really
> hope your students have other sources of good programming practice than
> their teacher.
Here is where I tend to disagree. I think that it is right in the
context of schooling that it may be required for students to be more
familiar than average with the language syntax and rules.
This is different than a work environment, where "time is money"[1], so
you want to make life easy for yourself and your colleagues, and if a
couple of parentheses can help, you should definitely use them.

[1] In a school context, on the other hand, priority should be knowledge.

David Brown

unread,
Jan 15, 2018, 11:10:06 AM1/15/18
to
On 15/01/18 16:08, Manfred wrote:
> On 1/15/2018 1:13 AM, David Brown wrote:
>> On 14/01/18 22:48, Stefan Ram wrote:
>>> Vir Campestris <vir.cam...@invalid.invalid> writes:
>>>> Please consider that future readers of your code may not have memorised
>>>> them all.
>>>
> <snip>
>>>
>>> Disclaimer: I don't know all precedence levels by heart,
>>> I look them up if need be. This is what I can
>>> write from my memory, but I'm just guessing, I'm not sure:
>>>
>> <snip mistakes>
>>>
>>> I'm sure I have made some mistakes and omissions above.
>>> As I said, I look up the precedence when I need to know it.
>>>
>>
>> It is simply /crazy/ to write code that where you have a reasonable
>> expectation that average programmers will have to look up a reference
>> manual to interpret it correctly.
>>
> I believe this is a bit hard as it is stated. I agree this is not good
> practice, but I wouldn't categorize as hard as crazy.
> Bad practice is not the same as crazy, I think. Besides, you wrote
> yourself that there are cases where code cannot be written to be easily
> readable.

Yes, I was a bit harsh. But there is a big difference between code that
has to be hard because it is a complex task, and knowingly making code
harder when there is a clear and obvious way to make it easier to
follow. For most operator expressions, the precedence is easy to see
and get right - but where it is not, you put in the extra parenthesis
(or split up the expression - there is no need to put everything in one
expression or one line).

>
>> Some types of code are naturally difficult - some code in C++ is
>> downright mystical even for the world's leading experts. You can
>> expect that it will be difficult for most people to understand - and
>> most people will use references when trying to interpret it.
>>
>> But most people will /not/ use references when reading or writing code
>> with operators. They will, like you, guess. And they will mostly get
>> it correct. Sometimes, however, they will get it wrong, especially
>> when using less common operators and combinations. "1<<4 + 5" is 512,
>> not 21. "(1 << 4) + 5" leaves no room for confusion.
>>
>> It is irresponsible to write code that it harder to understand than
>> necessary, for something as trivial as saving a couple of characters.
>> (If there are so many parenthesis that they become confusing, the
>> expression should be split up.)
> I tend to agree with the baseline, although I think that expression
> splitting serves more that readability only.

Yes. Splitting it up can make it easier to follow. It can give you
additional naming points to make the logic clearer. It can make types
more explicit (that is quite relevant in my line of work, where types
smaller than "int" are common and unsigned arithmetic is often used -
you can make your integer promotions explicit and force conversion to
unsigned types without needing casts). It can enforce the ordering of
evaluations, give you lines for breakpoints, make it easier to add
temporary "printf debugs", asserts, etc.

I very rarely use the comma operator because it can easily be
misinterpreted. /I/ know how it works, and can get the precedence
levels right most of the time even without looking up a reference - but
I certainly can't be sure that applies to everyone who might be reading
my code. So in most cases where I might think about using the comma
operator, or using the result of an assignment expression, I will
consider splitting up the expression instead. My aim is that where
possible, the code can be understood at a glance - it should be as easy
as possible to interpret it correctly, and as hard as possible to
interpret it incorrectly. Minimising the number of parenthesis or
keeping everything in one complicated expression is /way/ down in my
list of priorities.

>
> It is downright scary to hear this
>> attitude from someone who claims to teach C and C++ classes. I really
>> hope your students have other sources of good programming practice
>> than their teacher.
> Here is where I tend to disagree. I think that it is right in the
> context of schooling that it may be required for students to be more
> familiar than average with the language syntax and rules.
> This is different than a work environment, where "time is money"[1], so
> you want to make life easy for yourself and your colleagues, and if a
> couple of parentheses can help, you should definitely use them.

It is not about "time is money" - it is about making it as easy as
possible to be correct (in reading and writing code), and as hard as
possible to be wrong. Saving money (with reduced test/debug/re-code
cycles) is a bonus - writing quality code in the first place is the aim.

>
> [1] In a school context, on the other hand, priority should be knowledge.

Presumably at a school you are teaching people to be able to use the
language in the real world. You thus must teach them to write code in a
good way - as clearly as possible. You also, as a teacher, do not give
your students sample code that is so messy and obfuscated that you can't
understand it yourself without looking up the details!

Of course, you also have to teach the students to understand worse code
than you teach them to write - they will see all sorts of stuff in the
real world. But that is a minor part in comparison to teaching them
good practices.




James R. Kuyper

unread,
Jan 15, 2018, 12:09:39 PM1/15/18
to
On 01/14/2018 04:54 PM, Stefan Ram wrote:
[Re: precendence levels in C]
> Ok, now correcting, using notes:
>
> r...@zedat.fu-berlin.de (Stefan Ram) writes:

I forgot that this was comp.lang.c++, not comp.lang.c. I've corrected my
message accordingly:

To the extent that the rules of the C++ language can be described in
terms of operator precedence (which is a considerable extent), the
precedence levels correspond to the sub-sections 1-19 of section 8
(sub-section 20 doesn't quite fit into the precedence concept).

8.1: Primary expressions:
"literal"
this
>> (x) id_expression
[lambda_capture](parameter declaration){return result;}
[x ... y]

8.2: Postfix expressions.
>> x[...]
>> x....

Your notation is confusing, because the member selection operator blends
in with your ellipses. I assume you meant what I would describe using

x.member

>> x->...
>> x(...)
>
> Here, a new level should have started by writing
> an empty line.

No, this is not a different level.

>> x++
>> x++
>
> Was intended to read "x--".

(int){x, y}
(type_name_specifier){x, y}
int {x, y}
type_name_specifier {x, y}
x.template id_expression
x->template id_expression
x.~type_name
x->~type_name
dynamic_cast<type_id>(x)
static_cast<type_id>(x)
reinterpret_cast<type_id>(x)
const_cast<type_id>(x)
typeid(x)
typeid(type_id)

8.3: Unary operators
>> --x
>> ++x
>> -x
>> +x
>> !x
>> ~x
>
> forgot: &x, *x, sizeof x

alignof(type_name)
new type_id(x)
delete x
noexcept(x)

8.4: explicit type conversion (cast notation)
> forgot: (cast)x

8.5: Pointer-to-member operators
x.*y
x->*y

8.6: Multiplicative operators
>> x*y
>> x/y
>
> forgot: x%y

8.7: Additive operators
>> x+y
>> x-x

8.8: Bitwise shift operators
>> x<<y
>> x>>y

8.9: Relational operators
> Oops, a major omission: Totally forgot
> x<y, x>y, x<=y and x>=y here.

8.10: Equality operators
> x==y x!=y

8.11: Bitwise AND operator
>> x&y

8.13: Bitwise exclusive OR operator
>> x|y

8.12: Bitwise inclusive OR operator
>> x^y ???
> ^ is higher than |, I thought about that
> possibility, but was not sure.

8.14: Logical AND operator
>> x&&y

8.15: Logical OR operator
>> x||y

|| has lower precedence than &&.

8.16: Conditional operator
>> x?y:z (does not exactly fit)

To be precise, the way in which it fails to fit is that any expression
between the '?' and the ':' is evaluated in it's entirety, and used as
the second operand of the operator, so in that regard, ?: has lower
precedence than any other operator. However, with regard to its first
operand, it behaves as if it were just lower than ||. With respect ot
its third operand, it behaves exactly as if it had precedence just lower
than that of assignment expressions.

8.17: Throwing an exception
throw(x)

8.18: assignment operators
>> x = y
>> x += y and so on

8.19: Comma operator
>> x,y

Manfred

unread,
Jan 15, 2018, 1:16:42 PM1/15/18
to
On 1/15/2018 5:09 PM, David Brown wrote:
> On 15/01/18 16:08, Manfred wrote:
>> On 1/15/2018 1:13 AM, David Brown wrote:
<snip>
>> It is downright scary to hear this
>>> attitude from someone who claims to teach C and C++ classes. I really
>>> hope your students have other sources of good programming practice
>>> than their teacher.
>> Here is where I tend to disagree. I think that it is right in the
>> context of schooling that it may be required for students to be more
>> familiar than average with the language syntax and rules.
>> This is different than a work environment, where "time is money"[1], so
>> you want to make life easy for yourself and your colleagues, and if a
>> couple of parentheses can help, you should definitely use them.
>
> It is not about "time is money" - it is about making it as easy as
> possible to be correct (in reading and writing code), and as hard as
> possible to be wrong. Saving money (with reduced test/debug/re-code
> cycles) is a bonus - writing quality code in the first place is the aim.
>
>>
>> [1] In a school context, on the other hand, priority should be knowledge.
>
> Presumably at a school you are teaching people to be able to use the
> language in the real world. You thus must teach them to write code in a
> good way - as clearly as possible. You also, as a teacher, do not give
> your students sample code that is so messy and obfuscated that you can't
> understand it yourself without looking up the details!
Yes, the teacher should be familiar with what he is teaching.

>
> Of course, you also have to teach the students to understand worse code
> than you teach them to write - they will see all sorts of stuff in the
> real world. But that is a minor part in comparison to teaching them
> good practices.
>

My point about schooling stems from an observation about general
schooling of our world:
In the context of (human) language teaching (e.g. primary or middle
school), be it English, German, French, Chinese, whatever, I would
understand, even appreciate, that students be encouraged to use a
language that is somewhat more formal than commonly used, i.e. make a
wider use of the language rules, even those that are not commonly used,
for the sake of getting acquainted with the rules themselves.
On the other hand, when someone becomes a journalist, then it is
perfectly understandable to stick to a plain and simple style of
writing, to facilitate immediate comprehension by the public.

I believe one consequence of having the school sticking to mimic "the
real world" (and avoid going beyond what is of common use) is that it is
nowadays so common to read incorrect grammar everywhere, from private
email to published newspapers - which is a symptom of widespread ignorance.

Back to the topic of teaching how to code (which I would not be able to
do), yes "keeping things simple" is a major programming skill that
/must/ be taught, nonetheless I would keep in mind the difference I
tried to exemplify above between the school and the "real world": even
if a good programmer produces code that is as simple and clear as
possible, the student should be able to handle complex constructs, and
in order to do that he must have used them - so better use them at
school than at work.

Vir Campestris

unread,
Jan 15, 2018, 4:58:10 PM1/15/18
to
On 15/01/2018 00:13, David Brown wrote:
> It is simply /crazy/ to write code that where you have a reasonable
> expectation that average programmers will have to look up a reference
> manual to interpret it correctly.

Thank you. I am not alone.

Andy

David Brown

unread,
Jan 16, 2018, 4:53:07 AM1/16/18
to
People learning a language need to learn both the correct language
rules, and informal usage.

> On the other hand, when someone becomes a journalist, then it is
> perfectly understandable to stick to a plain and simple style of
> writing, to facilitate immediate comprehension by the public.

Plain, simple, but /correct/ - which is different from the language you
might use for writing a high-brow novel, and also different from the
language you would use at the pub.

>
> I believe one consequence of having the school sticking to mimic "the
> real world" (and avoid going beyond what is of common use) is that it is
> nowadays so common to read incorrect grammar everywhere, from private
> email to published newspapers - which is a symptom of widespread ignorance.

There are many reasons for this - but I don't think it is because
schools teach kids that "I was, like, LOL!!!! See U l8r" is appropriate
for serious communication.

>
> Back to the topic of teaching how to code (which I would not be able to
> do), yes "keeping things simple" is a major programming skill that
> /must/ be taught, nonetheless I would keep in mind the difference I
> tried to exemplify above between the school and the "real world": even
> if a good programmer produces code that is as simple and clear as
> possible, the student should be able to handle complex constructs, and
> in order to do that he must have used them - so better use them at
> school than at work.

I believe you are misunderstanding me.

I am not recommending limiting programming, or limiting teaching of
programming, to simple things. As Einstein said, "Everything should be
as simple as it can be, but no simpler". Students of a programming
language must certainly be able to understand more complex code, and
writing it should be part of their training (depending on the level of
the course).

I have been talking about code /clarity/, not simplicity. If you are
doing a complex task, the code will be complex - it does not have to be
unclear, even though it is difficult to understand. What I am against
is code that /could/ be easy to understand, but isn't - and I am
certainly against knowingly and intentionally writing code like that.
Whether code is simple or complex, it should be written with an aim of
making it clear. Write it so that your first impressions and quick
glance at the code matches the reality of it. Write it so that when you
look more at the details, it is still consistent. Write is so that when
you fully understand it, it still means the same thing. There should be
/no/ surprises under way in terms of /what/ the code does - even though
there may be surprises or unfamiliar techniques in terms of /how/ it
does it.

There can often be judgement calls about how much experience or
knowledge you expect from readers of the code - how much it is
reasonable to expect them to know straight away, and how much they may
have to look up. You don't want your code to be overly verbose just in
case it is a complete newbie that is looking at it. But in this case we
are talking about subtle precedences with relatively rarely user
operator combinations that even experts (including the person writing
the code) might need to look up in reference manuals, and where all the
risk of errors or misunderstandings can be avoided by just adding a pair
of parenthesis. I stand by my judgement that it is crazy to write such
code, and irresponsible to do so in a teaching situation.



Richard

unread,
Jan 16, 2018, 1:08:28 PM1/16/18
to
[Please do not mail me a copy of your followup]

Vir Campestris <vir.cam...@invalid.invalid> spake the secret code
<p3j857$oj6$4...@dont-email.me> thusly:
I would change "average programmers" to "average programmers on your
team" before I would agree with the statement.

We can work to increase the level of understanding of our teammates,
but we can't hold back because the entire world is not up to speed
yet.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Öö Tiib

unread,
Jan 16, 2018, 11:55:34 PM1/16/18
to
You are not alone. Tools also support view that precedence is not obvious.
For example clang assumes that in average we have forgot the precedence
of && and || and so it suggests (with -Wall) parentheses around &&.

Note that the parentheses and whitespaces are just cosmetics. The real
question is what to do if we reached EOF and ferror(in) returns not
zero. ;)

Bonita Montero

unread,
Jan 18, 2018, 7:34:37 AM1/18/18
to
> Please consider that future readers of your
> code may not have memorised them all.

It is easy to memorize that the comma-operator has the
lowest precedence.

Tim Rentsch

unread,
Jan 25, 2018, 1:46:51 PM1/25/18
to
Vir Campestris <vir.cam...@invalid.invalid> writes:

> On 13/01/2018 19:06, Bonita Montero wrote:
>
>> But in this case you can omit the parenthesis around
>> "(c = fgetc (in))" becuase the comma-operator has the
>> lowest precedence.
>
> I just looked. There are 17 levels of operator precedence.

17, and counting. The latest C++ standard draft has an additional
level for the new <=> operator.

Incidentally, C++ has one more level than C, because of going
through pointer-to-member values. In retrospect I think it might
have been better if the syntax for using pointer-to-member access
were

postfix-expression . ( expression )
postfix-expression -> ( expression )

so using pointer-to-member could fold in naturally into the
existing syntax, rather than having to add a level. (Disclaimer:
I have done no checking for possible ambiguities, etc.)

> Please consider that future readers of your code may not have
> memorised them all.

Anyone who has the necessary skills to be a competent software
developer can learn the syntax/precedence rules for expressions,
even in C++. The word "memorize" (or "memorise") isn't quite
right -- children memorize the order of letters in the alphabet,
which has an arbitrary order. The syntax for expressions is not
at all arbitrary but explicitly chosen for reasons that are (at
least mostly) good ones. That makes it easier to learn than an
arbitrary order like letters in an alphabet. Speaking of which,
there are (in English) 26 letters in the alphabet, and we expect
everyone will have memorized that order. A mere 17 levels is a
piece of cake.

Furthermore, anyone who is serious about being a good developer
should aspire to know the syntax/precedence rules without having
to look them up (if they don't know them already). Appeals to
concern over "the average programmer" displays an attitude of
excusing thinking that is sloppy, lazy, or careless. That's
self-reinforcing in the wrong direction: if it's expected that
someone's thinking will be sloppy, lazy, or careless, it will be;
conversely, if it's expected that their thinking will not be
sloppy, lazy, or careless, it won't be. (Or perhaps the person
in question will leave to seek out another profession, which is
also a good result.) It wouldn't be a bad idea to tell new hires
that at the end of a week they would be tested on knowing the
language expression precedence rules, and anyone who failed the
test be let go. Even better, tell them (before they come in)
that they will be tested on that during the interview.

Interesting anecdote -- where I went to school, there was course
for people who were Chemistry majors that gave the following
test (announced in advance as being closed book): student is
given a piece of paper with a blank periodic table on it, and
instructed to fill in the names/symbols for the elements, in
their appropriate boxes.

Other disciplines take their education seriously. So should
software developers.

asetof...@gmail.com

unread,
Jan 25, 2018, 3:02:40 PM1/25/18
to
In one ideal language one has to remember the minimum possible
for the language (so one easy language)
because one have to think to the algorithm and see the loop

Vir Campestris

unread,
Jan 25, 2018, 4:04:06 PM1/25/18
to
Absolutely.

To me the language is a way to get things done, not a means in itself.

Tim & I will have to disagree over that, just as we disagree on minor
points of English vs American.

Andy

Tim Rentsch

unread,
Jan 30, 2018, 8:51:45 PM1/30/18
to
Do you mean programming languages should be designed so there
isn't very much to remember?

The Smalltalk language has just three levels of precedence, and
binary operators (the middle precedence level) are grouped
strictly left-to-right (unless parentheses are used, of course).
(Smalltalk also has some related constructs that might be
considered another level of precedence or two.) The whole
language has just three keywords. Also, control structures (eg,
if/then/else, for, while) are expressed using the same syntax
as expressions, so there is less to remember there.

APL has no levels of precedence to remember: all expressions
are grouped right-to-left, again with parentheses available
to pick a different grouping.

Languages like Forth and PostScript have /no/ precedence and /no/
parentheses - evaluation is strictly left-to-right. PostScript
uses braces ({}) to enclose unevaluated code fragments, which
are then used with special operators to provide if/then/else,
for loops, etc.

Each of these cases has some nice properties and also some other
properties that are not as nice. Personally I think a happy
medium is a better path: trading a little bit of expression
complexity (and expressiveness) for having to remember a somewhat
bigger syntax has a positive ROI, up to a point. I don't know
what that point it but it definitely seems higher than the
"syntactically minimalist" languages like those mentioned
above.

Tim Rentsch

unread,
Jan 30, 2018, 9:04:32 PM1/30/18
to
Vir Campestris <vir.cam...@invalid.invalid> writes:

> On 25/01/2018 20:01, asetof...@gmail.com wrote:
>
>> In one ideal language one has to remember the minimum possible
>> for the language (so one easy language)
>> because one have to think to the algorithm and see the loop
>
> Absolutely.
>
> To me the language is a way to get things done, not a means in itself.
>
> Tim & I will have to disagree over that,

I haven't said anything about it. Why do you think we
would disagree?

> just as we disagree on minor
> points of English vs American.

I don't "disagree" about differences between British English and
American English, any more than the difference between French and
German. They are different languages, that's all (or different
dialects of the same language, some would say). For that matter
American English itself has a fair number of regional dialects.
For an example see the movie "Airplane!".
0 new messages