f



Aargh! Don't do this!

I encountered this gem in libuuid.

   typedef unsigned char uuid_t[16];

Which leads to the following fun behavior.

   #include <stdio.h>
   #include <uuid/uuid.h>

   static void uuid_fn(uuid_t uuid)
   {
       printf("sizeof uuid = %zu\n", sizeof uuid);
   }

   int main(void)
   {
       uuid_t uuid;

       printf("sizeof uuid = %zu\n", sizeof uuid);
       uuid_fn(uuid);

       return 0;
   }

   $ ./uuid-test
   sizeof uuid = 16
   sizeof uuid = 8

(Fortunately, gcc does warn about the sizeof operator in uuid_fn.)

Any reason that I shouldn't be irritated with whoever came up with
this?

-- 
========================================================================
Ian Pilcher                                         arequipeno@gmail.com
-------- "I grew up before Mark Zuckerberg invented friendship" --------
========================================================================
0
Ian
11/26/2015 3:44:33 PM
comp.lang.c 30657 articles. 4 followers. spinoza1111 (3246) is leader. Post Follow

857 Replies
1855 Views

Similar Articles

[PageSpeed] 3

On 26/11/15 16:44, Ian Pilcher wrote:
> I encountered this gem in libuuid.
> 
>   typedef unsigned char uuid_t[16];
> 
> Which leads to the following fun behavior.
> 
>   #include <stdio.h>
>   #include <uuid/uuid.h>
> 
>   static void uuid_fn(uuid_t uuid)
>   {
>       printf("sizeof uuid = %zu\n", sizeof uuid);
>   }
> 
>   int main(void)
>   {
>       uuid_t uuid;
> 
>       printf("sizeof uuid = %zu\n", sizeof uuid);
>       uuid_fn(uuid);
> 
>       return 0;
>   }
> 
>   $ ./uuid-test
>   sizeof uuid = 16
>   sizeof uuid = 8
> 
> (Fortunately, gcc does warn about the sizeof operator in uuid_fn.)
> 
> Any reason that I shouldn't be irritated with whoever came up with
> this?
> 

You would be irritated with the original designers of C, and probably of
the older languages that inspired it - but I think irritation is
justified for such things.

Sometimes it is safer to do your sizeof's on types, rather than variables.

And for passing array types around safely, you can do this:

typedef struct {
	unsigned char s[16];
} uuid_t;

Then your sizeof should work in the natural way (as well as making your
function safe against passing different sized arrays).  Of course, such
a change is not easy if you are using an external library!


0
David
11/26/2015 3:52:53 PM
Ian Pilcher <arequipeno@gmail.com> writes:

> I encountered this gem in libuuid.
>
>   typedef unsigned char uuid_t[16];
>
> Which leads to the following fun behavior.
>
>   #include <stdio.h>
>   #include <uuid/uuid.h>
>
>   static void uuid_fn(uuid_t uuid)
>   {
>       printf("sizeof uuid = %zu\n", sizeof uuid);
>   }
>
>   int main(void)
>   {
>       uuid_t uuid;
>
>       printf("sizeof uuid = %zu\n", sizeof uuid);
>       uuid_fn(uuid);
>
>       return 0;
>   }
>
>   $ ./uuid-test
>   sizeof uuid = 16
>   sizeof uuid = 8
>
> (Fortunately, gcc does warn about the sizeof operator in uuid_fn.)

Yes, that's a nice warning.  Never seen it before (pats self on head).

> Any reason that I shouldn't be irritated with whoever came up with
> this?

No, by all means be irritated.  It's not clear, though, who you should
be most irritated with.

Just for fun, another way to fix it is to pass a pointer to a uuid:

  static void uuid_fn(uuid_t *uuid)
  {
     printf("sizeof uuid = %zu\n", sizeof *uuid);
  }

Now, no one would do sizeof uuid because it's obviously a pointer, but
you might end up pushing the surprise somewhere else.

-- 
Ben.
0
Ben
11/26/2015 4:15:15 PM
On Thursday, November 26, 2015 at 10:15:32 AM UTC-6, Ben Bacarisse wrote:
> No, by all means be irritated.  It's not clear, though, who you should
> be most irritated with.

I'd focus my irritation on whoever formulated the rule that array types
specified as such in prototypes are treated within the function as pointers,
rather than as indirectly-stored array-type lvalues.  Having arrays devolve
to pointer types was a necessity before prototypes were invented, but when
prototypes were added it should have been possible to say that given:

    void foo1(int *a);
    void foo2(int a[23]);
    void foo3(int (*a)[23]);
    void foo3(int (*a)[]);

The second would receive 'a' passed by value (with a warning, if one is
enabled for passing structures by value); the first would receive the
address of the first element of a, the third would receive a pointer to
a 23-element array, and the last would receive a pointer to the first
element of an array of unknown size (using sizeof on the array would
not work).  The difference between the first and fourth would be that a
compiler which received multiple arrays of the same type would be entitled
to assume that only like-numbered elements could alias, but a compiler
would have to assume that an integer pointer could alias any member of an
integer array.



0
supercat
11/26/2015 4:29:59 PM
On Thu, 2015-11-26, David Brown wrote:
> On 26/11/15 16:44, Ian Pilcher wrote:
>> I encountered this gem in libuuid.
>> 
>>   typedef unsigned char uuid_t[16];
....
>> Any reason that I shouldn't be irritated with whoever came up with
>> this?
>
> You would be irritated with the original designers of C, and probably of
> the older languages that inspired it - but I think irritation is
> justified for such things.

Having the language allow it is one thing; being ignorant enough to
use it is another.

> Sometimes it is safer to do your sizeof's on types, rather than variables.
>
> And for passing array types around safely, you can do this:
>
> typedef struct {
> 	unsigned char s[16];
> } uuid_t;

And that's a technique that people have used since the early 1980s at
least.  See struct ether_addr, struct in6_addr and so on in
BSD/Unix/Linux.

And yet I repeatedly see APIs where things like these are --
yes, typedef:ed arrays.  Grrr.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/26/2015 6:43:56 PM
On Thu, 26 Nov 2015 09:44:33 -0600, Ian Pilcher wrote:
> I encountered this gem in libuuid.
> 
>    typedef unsigned char uuid_t[16];
> 
> Which leads to [...] fun behavior.
[snip example]
> Any reason that I shouldn't be irritated with whoever came up with
> this?

Irritation is a reasonable reaction.  Avoid typedefs with array types,
because they behave very surprisingly when used as function parameters
(as you have noticed).  It can get even weirder:

  int foo(uuid_t *x);

  void bar(void)
  {
     uuid_t x;
     foo(&x); /* this is OK */
  }

  void baz(uuid_t x)
  {
     foo(&x); /* this is not OK (type error) */
  }

Incidentally, the standard allows va_list to be an array typedef,
and some implementations actually do it.
0
Nick
11/26/2015 7:25:04 PM
I Never do that, I never pass
array of objects as all type.
I always pass the array just as pointer always

0
asetofsymbols
11/26/2015 8:06:26 PM
On Thursday, November 26, 2015 at 1:27:43 PM UTC-6, Nick Bowler wrote:
> Incidentally, the standard allows va_list to be an array typedef,
> and some implementations actually do it.

I've seen that behavior with va_list; it has the side-effect that if one
passes a va_list to a function which consumes its arguments, the arguments
will be unavailable to the caller.  I suppose there are times that might
be handy, but in C89 it precluded the possibility of a e.g. having a
vsprintf-style function parse its arguments once to find out how much space
was required, then allocate the space and then rerun the function to store
the data.  Fortunately, C99 added va_copy to fix that weakness.
0
supercat
11/26/2015 8:48:25 PM
Ian Pilcher wrote:
> I encountered this gem in libuuid.
>
>     typedef unsigned char uuid_t[16];
>
> Which leads to the following fun behavior.
>
>     #include <stdio.h>
>     #include <uuid/uuid.h>
>
>     static void uuid_fn(uuid_t uuid)
>     {
>         printf("sizeof uuid = %zu\n", sizeof uuid);
>     }

A good justification for reference parameters!

-- 
Ian Collins
0
Ian
11/26/2015 8:51:40 PM
On Thursday, November 26, 2015 at 2:51:50 PM UTC-6, Ian Collins wrote:
> A good justification for reference parameters!

Actually, there should be a variety of parameter kinds based upon who would be
allowed to change the values in question during the execution of the function,
and whether the function would be allowed to persist the value afterward.  I
find it interesting that there isn't more enthusiasm for "restrict" parameters,
since given:

   void foo(int * restrict p);
   void bar(void);
   int test(void)
   {
     int x;
     foo(&x);
     x++;
     bar();
     return x;
   }

the restrict qualifier on "foo" would allow a compiler to safely keep x
in a register across the call to bar() since there would be no way bar()
could possibly modify x.  Perhaps enthusiasm for "restrict" might increase
if it were legal to take the address of a register variable, but only in
cases where it was immediately placed in a "restrict" pointer, and the
variable was not used during the lifetime of that pointer.  Given those
rules, it would be legal for the compiler to store the variable into
memory before its address was taken, and read it back into a register at
any convenient time between the lifetime of its "taken address" and the
time it was next used as a variable.  Such rules could also be applied to
union members (at present, it's legal to take the address of a variable
within a union, but it doesn't seem to be legal to do much with it).
0
supercat
11/26/2015 10:24:01 PM
On 11/26/2015 04:24 PM, supercat@casperkitty.com wrote:
> Actually, there should be a variety of parameter kinds based upon who would be
> allowed to change the values in question during the execution of the function,
> and whether the function would be allowed to persist the value afterward.  I
> find it interesting that there isn't more enthusiasm for "restrict" parameters,
> since given:

Frankly, I think that the lack of enthusiasm for restrict is based
mostly on a lack of understanding.  (And I'm saying this because I've
read a fair number of web pages on the subject, and I don't understand
it.)

-- 
========================================================================
Ian Pilcher                                         arequipeno@gmail.com
-------- "I grew up before Mark Zuckerberg invented friendship" --------
========================================================================
0
Ian
11/26/2015 10:49:33 PM
supercat@casperkitty.com wrote:
> On Thursday, November 26, 2015 at 2:51:50 PM UTC-6, Ian Collins wrote:
>> A good justification for reference parameters!
>
> Actually, there should be a variety of parameter kinds based upon who would be
> allowed to change the values in question during the execution of the function,
> and whether the function would be allowed to persist the value afterward.  I
> find it interesting that there isn't more enthusiasm for "restrict" parameters,
> since given:
>
>     void foo(int * restrict p);
>     void bar(void);
>     int test(void)
>     {
>       int x;
>       foo(&x);
>       x++;
>       bar();
>       return x;
>     }
>
> the restrict qualifier on "foo" would allow a compiler to safely keep x
> in a register across the call to bar() since there would be no way bar()
> could possibly modify x.

Are you confusing restrict with const?

-- 
Ian Collins
0
Ian
11/26/2015 11:57:53 PM
Geoff <geoff@invalid.invalid> writes:
[...]
> MISRA Rule 61: 
> Every non-empty case clause in a switch statement shall be terminated
> with a break statement.

So much for Duff's device!

-- 
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"
0
Keith
11/27/2015 1:01:01 AM
On 26-Nov-15 16:24, supercat@casperkitty.com wrote:
> Ian Collins wrote:
>> A good justification for reference parameters!
> 
> Actually, there should be a variety of parameter kinds based upon who
> would be allowed to change the values in question during the
> execution of the function, and whether the function would be allowed
> to persist the value afterward.  I find it interesting that there
> isn't more enthusiasm for "restrict" parameters, since given:
> 
>    void foo(int * restrict p);
>    void bar(void);
>    int test(void)
>    {
>      int x;
>      foo(&x);
>      x++;
>      bar();
>      return x;
>    }
> 
> the restrict qualifier on "foo" would allow a compiler to safely keep
> x in a register across the call to bar() since there would be no way
> bar() could possibly modify x.

Incorrect.  The restriction applies within the block containing a
restricted pointer, which in this case is only foo().  The restriction
does _not_ somehow escape foo() and infect x within all of test().

OTOH, what you are looking for _would_ seem to apply in this case:

void foo(int *p);
void bar(void);
int test(int * restrict x)
{
  foo(x);
  *x++;
  bar(); // cannot access *x
  return *x;
}

However, I would be cautious here since none of the Standard's examples
of "restrict" include other function calls, so this may not have been
their intent and/or may not be how implementors interpret it.

> (at present, it's legal to take the address of a variable within a
> union, but it doesn't seem to be legal to do much with it).

Taking the address of one union member is fine, and accessing it is
fine; the problems come when doing that with  _multiple_ members.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/27/2015 3:17:29 AM
On 26/11/15 19:43, Jorgen Grahn wrote:
> On Thu, 2015-11-26, David Brown wrote:
>> On 26/11/15 16:44, Ian Pilcher wrote:
>>> I encountered this gem in libuuid.
>>>
>>>   typedef unsigned char uuid_t[16];
> ...
>>> Any reason that I shouldn't be irritated with whoever came up with
>>> this?
>>
>> You would be irritated with the original designers of C, and probably of
>> the older languages that inspired it - but I think irritation is
>> justified for such things.
> 
> Having the language allow it is one thing; being ignorant enough to
> use it is another.

Fair enough.  But C would be safer for array work if the language did
not have the tendency to decay arrays into pointers in cases like this.
 When C was first designed, the authors had a different balance between
language safety, and ease of efficient compiler implementation, than we
have now.  Some of these design flaws (seen with modern eyes) have been
fixed, such as the "implicit int".  Others, like this one or the
required "break" at the end of switch cases, are pretty much impossible
to fix without major compatibility issues.

So irritation at the language designers here is justified - but I can
agree that irritation at the people that don't understand the problem
and pass naked or typedef'd arrays as parameters is more appropriate.

> 
>> Sometimes it is safer to do your sizeof's on types, rather than variables.
>>
>> And for passing array types around safely, you can do this:
>>
>> typedef struct {
>> 	unsigned char s[16];
>> } uuid_t;
> 
> And that's a technique that people have used since the early 1980s at
> least.  See struct ether_addr, struct in6_addr and so on in
> BSD/Unix/Linux.

Damn, and I thought I could patent the idea :-)

> 
> And yet I repeatedly see APIs where things like these are --
> yes, typedef:ed arrays.  Grrr.
> 
> /Jorgen
> 

0
David
11/27/2015 8:33:35 AM
On 26/11/15 17:15, Ben Bacarisse wrote:
> Ian Pilcher <arequipeno@gmail.com> writes:
> 
>> I encountered this gem in libuuid.
>>
>>   typedef unsigned char uuid_t[16];
>>
>> Which leads to the following fun behavior.
>>
>>   #include <stdio.h>
>>   #include <uuid/uuid.h>
>>
>>   static void uuid_fn(uuid_t uuid)
>>   {
>>       printf("sizeof uuid = %zu\n", sizeof uuid);
>>   }
>>
>>   int main(void)
>>   {
>>       uuid_t uuid;
>>
>>       printf("sizeof uuid = %zu\n", sizeof uuid);
>>       uuid_fn(uuid);
>>
>>       return 0;
>>   }
>>
>>   $ ./uuid-test
>>   sizeof uuid = 16
>>   sizeof uuid = 8
>>
>> (Fortunately, gcc does warn about the sizeof operator in uuid_fn.)
> 
> Yes, that's a nice warning.  Never seen it before (pats self on head).
> 

It is -Wsizeof-array-argument, enabled by default.

A related warning is -Wsizeof-pointer-memaccess (in -Wall) from gcc 4.8,
that warns about suspicious use of things like "memcpy (&foo, ptr,
sizeof (&foo))"

<https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wno-sizeof-pointer-memaccess-552>

>> Any reason that I shouldn't be irritated with whoever came up with
>> this?
> 
> No, by all means be irritated.  It's not clear, though, who you should
> be most irritated with.
> 
> Just for fun, another way to fix it is to pass a pointer to a uuid:
> 
>   static void uuid_fn(uuid_t *uuid)
>   {
>      printf("sizeof uuid = %zu\n", sizeof *uuid);
>   }
> 
> Now, no one would do sizeof uuid because it's obviously a pointer, but
> you might end up pushing the surprise somewhere else.
> 

0
David
11/27/2015 8:40:30 AM
On 26/11/15 23:49, Ian Pilcher wrote:
> On 11/26/2015 04:24 PM, supercat@casperkitty.com wrote:
>> Actually, there should be a variety of parameter kinds based upon who
>> would be
>> allowed to change the values in question during the execution of the
>> function,
>> and whether the function would be allowed to persist the value
>> afterward.  I
>> find it interesting that there isn't more enthusiasm for "restrict"
>> parameters,
>> since given:
> 
> Frankly, I think that the lack of enthusiasm for restrict is based
> mostly on a lack of understanding.  (And I'm saying this because I've
> read a fair number of web pages on the subject, and I don't understand
> it.)
> 

With supercat's post being a fine example of such lack of understanding!

0
David
11/27/2015 8:44:40 AM
On 26/11/15 23:24, supercat@casperkitty.com wrote:
> On Thursday, November 26, 2015 at 2:51:50 PM UTC-6, Ian Collins wrote:
>> A good justification for reference parameters!
> 
> Actually, there should be a variety of parameter kinds based upon who would be
> allowed to change the values in question during the execution of the function,
> and whether the function would be allowed to persist the value afterward.  I
> find it interesting that there isn't more enthusiasm for "restrict" parameters,
> since given:
> 
>    void foo(int * restrict p);
>    void bar(void);
>    int test(void)
>    {
>      int x;
>      foo(&x);
>      x++;
>      bar();
>      return x;
>    }
> 
> the restrict qualifier on "foo" would allow a compiler to safely keep x
> in a register across the call to bar() since there would be no way bar()
> could possibly modify x.  Perhaps enthusiasm for "restrict" might increase
> if it were legal to take the address of a register variable, but only in
> cases where it was immediately placed in a "restrict" pointer, and the
> variable was not used during the lifetime of that pointer.  Given those
> rules, it would be legal for the compiler to store the variable into
> memory before its address was taken, and read it back into a register at
> any convenient time between the lifetime of its "taken address" and the
> time it was next used as a variable.  Such rules could also be applied to
> union members (at present, it's legal to take the address of a variable
> within a union, but it doesn't seem to be legal to do much with it).
> 

I think you mean:

void foo(const int *p);

"restrict" has nothing to do with it - it is "const" that means "read-only".

It doesn't matter that it is illegal to take the address of a register
variable - baring very specialist uses (such as an embedded program
dedicating a cpu register to a specific variable), "register" variables
are almost non-existent in modern programming.  Compilers generally
ignore the "register" keyword, other than to check that you can't take
its address.

Like "auto", the "register" keyword should be deprecated in its current
use, ready for recycling to something useful.

0
David
11/27/2015 8:52:53 AM
On 27-Nov-15 02:33, David Brown wrote:
> Some of these design flaws (seen with modern eyes) have been fixed,
> such as the "implicit int". Others, like this one or the required
> "break" at the end of switch cases, are pretty much impossible to fix
> without major compatibility issues.

I like how C# "fixed" that flaw: every non-empty case must end with a
break, goto, continue, etc. rather than falling through; to get C's
fall-through behavior, one must goto the next case label explicitly.

Doing the same in C itself would obviously break _some_ existing code,
but probably not much; intentional fall-through seems rare in practice.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/27/2015 9:51:04 AM
On 27/11/2015 09:51, Stephen Sprunk wrote:
> On 27-Nov-15 02:33, David Brown wrote:
>> Some of these design flaws (seen with modern eyes) have been fixed,
>> such as the "implicit int". Others, like this one or the required
>> "break" at the end of switch cases, are pretty much impossible to fix
>> without major compatibility issues.
>
> I like how C# "fixed" that flaw: every non-empty case must end with a
> break, goto, continue, etc. rather than falling through; to get C's
> fall-through behavior, one must goto the next case label explicitly.
>
> Doing the same in C itself would obviously break _some_ existing code,
> but probably not much; intentional fall-through seems rare in practice.

Not really:

     switch (c) {
     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
      ....
     }

-- 
Bartc
0
BartC
11/27/2015 10:34:48 AM
Stephen Sprunk <stephen@sprunk.org> writes:

> On 26-Nov-15 16:24, supercat@casperkitty.com wrote:
>> Ian Collins wrote:
>>> A good justification for reference parameters!
>> 
>> Actually, there should be a variety of parameter kinds based upon who
>> would be allowed to change the values in question during the
>> execution of the function, and whether the function would be allowed
>> to persist the value afterward.  I find it interesting that there
>> isn't more enthusiasm for "restrict" parameters, since given:
>> 
>>    void foo(int * restrict p);
>>    void bar(void);
>>    int test(void)
>>    {
>>      int x;
>>      foo(&x);
>>      x++;
>>      bar();
>>      return x;
>>    }
>> 
>> the restrict qualifier on "foo" would allow a compiler to safely keep
>> x in a register across the call to bar() since there would be no way
>> bar() could possibly modify x.
>
> Incorrect.  The restriction applies within the block containing a
> restricted pointer, which in this case is only foo().  The restriction
> does _not_ somehow escape foo() and infect x within all of test().
>
> OTOH, what you are looking for _would_ seem to apply in this case:
>
> void foo(int *p);
> void bar(void);
> int test(int * restrict x)
> {
>   foo(x);
>   *x++;
>   bar(); // cannot access *x
>   return *x;
> }
>
> However, I would be cautious here since none of the Standard's examples
> of "restrict" include other function calls, so this may not have been
> their intent and/or may not be how implementors interpret it.

I think it's clearly intended to be as you say.  The conditions on
accesses apply during the execution of the block associated with the
restrict-qualified pointer, and that is clarified a being "that portion
of the execution of the program that would correspond to the lifetime of
an object with scalar type and automatic storage duration associated
with [the block]".  The lifetime of such an object spans nested function
calls.

<snip>
-- 
Ben.
0
Ben
11/27/2015 10:36:54 AM
On 27/11/15 11:34, BartC wrote:
> On 27/11/2015 09:51, Stephen Sprunk wrote:
>> On 27-Nov-15 02:33, David Brown wrote:
>>> Some of these design flaws (seen with modern eyes) have been fixed,
>>> such as the "implicit int". Others, like this one or the required
>>> "break" at the end of switch cases, are pretty much impossible to fix
>>> without major compatibility issues.
>>
>> I like how C# "fixed" that flaw: every non-empty case must end with a
>> break, goto, continue, etc. rather than falling through; to get C's
>> fall-through behavior, one must goto the next case label explicitly.
>>
>> Doing the same in C itself would obviously break _some_ existing code,
>> but probably not much; intentional fall-through seems rare in practice.
> 
> Not really:
> 
>     switch (c) {
>     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
>      ....
>     }
> 

It would be fine to allow multiple case labels in a row to "fall
through", although obviously it would be better to have a decent syntax
for multiple labels ("case 'A' ... 'D', 'F' : ").  I don't know C#, but
Stephen said that the no fall-through rule applies specifically to
non-empty cases.

However, as always the C pre-processor gives scope for making a muck-up:

#ifdef DOSOMETHING_WITH_A
#define DOSOMETHING() doSomething();
#else
#define DOSOMETHING()
#endif

switch (c) {
	case 'A' :
		// Maybe do something extra in this case
		DOSOMETHING()
		// Then fall-through to AB handling
	case 'B' :
		doAB();
		break;
	}

So there is little chance of this being changed in C.  The best we could
do is hope that compilers could warn on cases that C# disallows.


0
David
11/27/2015 11:31:25 AM
On Fri, 2015-11-27, David Brown wrote:
> On 26/11/15 19:43, Jorgen Grahn wrote:
>> On Thu, 2015-11-26, David Brown wrote:
....
>>> And for passing array types around safely, you can do this:
>>>
>>> typedef struct {
>>> 	unsigned char s[16];
>>> } uuid_t;
>> 
>> And that's a technique that people have used since the early 1980s at
>> least.  See struct ether_addr, struct in6_addr and so on in
>> BSD/Unix/Linux.
>
> Damn, and I thought I could patent the idea :-)

Yeah ;-)

For the record, I wasn't implying that you believed it was an original
idea of yours -- I just thought it remarkable that people like you and
me still have to point it out.

Being the Keeper of Lost Knowledge can become a bit tedious.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/27/2015 2:06:10 PM
On Fri, 2015-11-27, BartC wrote:
> On 27/11/2015 09:51, Stephen Sprunk wrote:
>> On 27-Nov-15 02:33, David Brown wrote:
>>> Some of these design flaws (seen with modern eyes) have been fixed,
>>> such as the "implicit int". Others, like this one or the required
>>> "break" at the end of switch cases, are pretty much impossible to fix
>>> without major compatibility issues.
>>
>> I like how C# "fixed" that flaw: every non-empty case must end with a
>> break, goto, continue, etc. rather than falling through; to get C's
>> fall-through behavior, one must goto the next case label explicitly.
>>
>> Doing the same in C itself would obviously break _some_ existing code,
>> but probably not much; intentional fall-through seems rare in practice.
>
> Not really:
>
>      switch (c) {
>      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
>       ....
>      }

Same here; I use fallthrough quite often.  20% of my switch
statements, maybe?

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/27/2015 2:08:07 PM
In article <slrnn5gou5.5q5.grahn+nntp@frailea.sa.invalid>,
Jorgen Grahn  <grahn+nntp@snipabacken.se> wrote:
....
>>> Doing the same in C itself would obviously break _some_ existing code,
>>> but probably not much; intentional fall-through seems rare in practice.
>>
>> Not really:
>>
>>      switch (c) {
>>      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
>>       ....
>>      }
>
>Same here; I use fallthrough quite often.  20% of my switch
>statements, maybe?

As noted originally, and re-inforced since, the key is "non-empty switch
statements".  That is, everybody is OK with:

      case 'A':
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F':
	/* Common code for A-F */

What they are not so happy with is:

      case 'A':
	/* Special code only for A */
      case 'B':
	/* Code for A or B */
      case 'C':
	/* etc */
      case 'D':
      case 'E':
      case 'F':
	/* Common code for A-F */

-- 
They say compassion is a virtue, but I don't have the time!

    - David Byrne -

0
gazelle
11/27/2015 3:24:52 PM
On Thursday, November 26, 2015 at 9:17:44 PM UTC-6, Stephen Sprunk wrote:
> On 26-Nov-15 16:24, supercat wrote:
> >    void foo(int * restrict p);
> >    void bar(void);
> >    int test(void)
> >    {
> >      int x;
> >      foo(&x);
> >      x++;
> >      bar();
> >      return x;
> >    }
> > 
> > the restrict qualifier on "foo" would allow a compiler to safely keep
> > x in a register across the call to bar() since there would be no way
> > bar() could possibly modify x.
> 
> Incorrect.  The restriction applies within the block containing a
> restricted pointer, which in this case is only foo().  The restriction
> does _not_ somehow escape foo() and infect x within all of test().

The restriction says nothing about what "test" may do with x, but if foo()
were copy the passed-in address somewhere before it returned, that copy
would be bound to the restrict-qualified parameter and would become invalid
once that parameter left scope (i.e. after "foo" returned).  There would
thus be no possibility of "bar" using it.  Since there is no other way in
which "bar" could acquire the address of x, it is thus impossible for bar()
to access it.

If "test" had passed &x as a non-restrict-qualified argument to some other
function prior to calling "bar", then a compiler which couldn't see into
that other function nor into "bar" would have no way of knowing whether
"bar" might modify x, but if the only functions to which the address is
given have restrict qualifiers, that would imply that the address of x
cannot "escape".

> > (at present, it's legal to take the address of a variable within a
> > union, but it doesn't seem to be legal to do much with it).
> 
> Taking the address of one union member is fine, and accessing it is
> fine; the problems come when doing that with  _multiple_ members.

I could see reading the Standard in such a way that it was legal to take the
address of multiple union members and use them in arbitrary sequence without
restriction.  I could also see a reading of the Standard in which it is
illegal to use a pointer of union-member type to access the union at all.
I see no way to read the Standard in such a fashion that would allow some
patterns of access but not all, since that would require that the effective
type of the storage occupied the union would change according to usage, and
there is nothing in N1570 to accommodate that.
0
supercat
11/27/2015 3:37:58 PM
On Friday, November 27, 2015 at 2:44:49 AM UTC-6, David Brown wrote:
> With supercat's post being a fine example of such lack of understanding!

Rereading the Standard, it seems that restrict pointers are allowed to leak,
for reasons I'm not quite clear about.  It would seem that having a qualifier
that could guarantee that a function won't cause a copy of a passed-in pointer
to be persisted would be one of the first things a language designer interested
in optimization would include, and I find it bizarre that C would go 35+ years
without ever bothering to add such a thing.
0
supercat
11/27/2015 3:51:45 PM
On 27/11/2015 15:24, Kenny McCormack wrote:
> In article <slrnn5gou5.5q5.grahn+nntp@frailea.sa.invalid>,
> Jorgen Grahn  <grahn+nntp@snipabacken.se> wrote:
> ...
>>>> Doing the same in C itself would obviously break _some_ existing code,
>>>> but probably not much; intentional fall-through seems rare in practice.
>>>
>>> Not really:
>>>
>>>       switch (c) {
>>>       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
>>>        ....
>>>       }
>>
>> Same here; I use fallthrough quite often.  20% of my switch
>> statements, maybe?
>
> As noted originally, and re-inforced since, the key is "non-empty switch
> statements".

OK, I missed that...

> That is, everybody is OK with:
>
>        case 'A':
>        case 'B':
>        case 'C':
>        case 'D':
>        case 'E':
>        case 'F':
> 	/* Common code for A-F */
>
> What they are not so happy with is:
>
>        case 'A':
> 	/* Special code only for A */
>        case 'B':
> 	/* Code for A or B */
>        case 'C':
> 	/* etc */
>        case 'D':
>        case 'E':
>        case 'F':
> 	/* Common code for A-F */

But I think there's another problem, which is that perhaps C#'s switch 
statements and case labels are properly structured.

C's aren't, even if most people write use them sensibly. case labels can 
be anywhere within the body of a switch, and it won't always make sense 
to follow them break, continue etc.

That is, if the code following one case label is a nested set of if, 
for, while, etc, then the next case can appear anywhere in that 
structure. Example:

int a,b,c;

switch (a){
  if (b==c) {
     case 10:
       b=10;
       if (a==1) {case 20:;}

}
}

-- 
Bartc

0
BartC
11/27/2015 4:08:13 PM
Ian Collins <ian-news@hotmail.com> wrote:

> Ian Pilcher wrote:
> > I encountered this gem in libuuid.
> >
> >     typedef unsigned char uuid_t[16];
> >
> > Which leads to the following fun behavior.
> >
> >     #include <stdio.h>
> >     #include <uuid/uuid.h>
> >
> >     static void uuid_fn(uuid_t uuid)
> >     {
> >         printf("sizeof uuid = %zu\n", sizeof uuid);
> >     }
> 
> A good justification for reference parameters!

*Shudder*

No.

Richard
0
raltbos
11/27/2015 4:46:09 PM
On Fri, 27 Nov 2015 07:37:58 -0800, supercat wrote:
> On Thursday, November 26, 2015 at 9:17:44 PM UTC-6, Stephen Sprunk wrote:
>> On 26-Nov-15 16:24, supercat wrote:
>> >    void foo(int * restrict p);
>> >    void bar(void);
>> >    int test(void)
>> >    {
>> >      int x;
>> >      foo(&x);
>> >      x++;
>> >      bar();
>> >      return x;
>> >    }
>> > 
>> > the restrict qualifier on "foo" would allow a compiler to safely keep
>> > x in a register across the call to bar() since there would be no way
>> > bar() could possibly modify x.
>> 
>> Incorrect.  The restriction applies within the block containing a
>> restricted pointer, which in this case is only foo().  The restriction
>> does _not_ somehow escape foo() and infect x within all of test().
> 
> The restriction says nothing about what "test" may do with x, but if foo()
> were copy the passed-in address somewhere before it returned, that copy
> would be bound to the restrict-qualified parameter and would become invalid
> once that parameter left scope (i.e. after "foo" returned).  There would
> thus be no possibility of "bar" using it.  Since there is no other way in
> which "bar" could acquire the address of x, it is thus impossible for bar()
> to access it.

This is actually not true, as the copying restrictions apply only in limited
cases.

The restriction on copying restrict pointer values is this:

  - P is a restrict-qualified pointer object associated with a block B.

  - If we assign a new value to P which is based on a different
    restricted pointer P2, associated with block B2, then B2 must
    either start before B, or B2 must end before the assignment.

All other copies are allowed, as far as restrict is concerned.

Note:

  - The copying restriction only applies to copying a value which is
    based on a restrict-qualified pointer object into another restrict
    qualified-pointer object.

  - Therefore, foo is allowed assign its argument into a pointer object
    that does not have the restrict qualifier.  This pointer object
    could easily be accessible from bar.

Example:

   int *sideband;

   void foo(int * restrict p)
   {
      sideband = p; /* allowed since sideband is not restrict-qualified. */
      *p = 0;
   }

   void bar(void)
   {
      *sideband += 42; /* allowed; p's associated block has ended */
   }

   int test(void)
   {
      int x;
      foo(&x);
      x++;
      bar();
      return x; /* returns 43 */
   }
0
Nick
11/27/2015 5:25:43 PM
On Friday, November 27, 2015 at 11:28:17 AM UTC-6, Nick Bowler wrote:
> This is actually not true, as the copying restrictions apply only in limited
> cases.

My point of confusion lay with the fact that if a restrict-qualified pointer
is copied to an ordinary pointer, the Standard will regard that ordinary
pointer as being "based upon" the restrict pointer, and I incorrectly
inferred that a pointer which was based upon a "restrict" pointer would
permanently inherit the effects thereof.  I'm actually not sure in what
cases it would be useful to have the effects of "restrict" wear off at the
end of the restrict pointer's lifetime; on the flip side, I can see many
cases where optimization could be enhanced if the effects were permanent.

Within the lifetime of a restrict pointer, operations on that pointer or
others based upon it are unsequenced relative to operations which are not
performed using those pointers.  If the effect were permanent, accesses
performed using pointers based on a restrict pointer would remain
unsequenced relative to all other accesses performed throughout the
universe [implying that the restrict pointers would remain valid only if
either (1) nothing wrote the objects in question via any means, or (2)
nothing in the universe ever accessed the object except through copies of
the restrict pointer].

In any case, I think any good language should include a means of passing
a pointer/reference to something in such a fashion that the recipient would
not be allowed to persist it in a way which would alias anything which is
used in the outside world and might change.  I wonder why "restrict" was not
given such semantics?
0
supercat
11/27/2015 6:42:49 PM
On 27 Nov 2015 14:08:07 GMT, Jorgen Grahn <grahn+nntp@snipabacken.se>
wrote:

>On Fri, 2015-11-27, BartC wrote:
>> On 27/11/2015 09:51, Stephen Sprunk wrote:
>>> On 27-Nov-15 02:33, David Brown wrote:
>>>> Some of these design flaws (seen with modern eyes) have been fixed,
>>>> such as the "implicit int". Others, like this one or the required
>>>> "break" at the end of switch cases, are pretty much impossible to fix
>>>> without major compatibility issues.
>>>
>>> I like how C# "fixed" that flaw: every non-empty case must end with a
>>> break, goto, continue, etc. rather than falling through; to get C's
>>> fall-through behavior, one must goto the next case label explicitly.
>>>
>>> Doing the same in C itself would obviously break _some_ existing code,
>>> but probably not much; intentional fall-through seems rare in practice.
>>
>> Not really:
>>
>>      switch (c) {
>>      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
>>       ....
>>      }
>
>Same here; I use fallthrough quite often.  20% of my switch
>statements, maybe?
>

MISRA Rule 61: 
Every non-empty case clause in a switch statement shall be terminated
with a break statement.

The reason C# enforces this with an error is because in practice,
unintended fall through was a source of more bugs than intentional
fall through was of practical use. 

In C, deliberate fall through should be documented as such with a
comment and in C# one must use goto case y; as "documentation". I
would contend that deliberate fall-through can and should be avoided.
I have also seen /* fallthrough */ comments at the default case in
legacy code where no such fall through existed. (All cases ended in
break;)

Swift also doesn't default to fall through and the break statement is
optional. Swift allows deliberate fall-through with the fallthrough
keyword, something I wish C# had instead of goto. 

Swift also requires every case be covered, allowing (requiring?) the
default case to cover them when there are holes in the cases.

It should be interesting to see how LLVM is going to implement C# now
that Microsoft has adopted it as their back-end and whether there will
be some opportunities for cross-pollination between the languages.

The newer languages have responded to the perceived need to avoid the
"Bad Practices"(tm) of the now-stagnant C language which seems to
cling to these legacy practices in the name of backward compatibility
even when it's a source of error.

C++'s fall through behavior is bizarre.
0
Geoff
11/27/2015 7:18:45 PM
On Fri, 27 Nov 2015 11:18:45 -0800, Geoff <geoff@invalid.invalid>
wrote:

>C++'s fall through behavior is bizarre.

I take this back. I misinterpreted a statement in the documentation.
C++'s switch-case behavior is no more bizarre than C's.
0
Geoff
11/27/2015 7:35:30 PM
On Fri, 2015-11-27, Geoff wrote:
> On 27 Nov 2015 14:08:07 GMT, Jorgen Grahn <grahn+nntp@snipabacken.se>
> wrote:
>
>>On Fri, 2015-11-27, BartC wrote:
>>> On 27/11/2015 09:51, Stephen Sprunk wrote:
>>>> On 27-Nov-15 02:33, David Brown wrote:
>>>>> Some of these design flaws (seen with modern eyes) have been fixed,
>>>>> such as the "implicit int". Others, like this one or the required
>>>>> "break" at the end of switch cases, are pretty much impossible to fix
>>>>> without major compatibility issues.
>>>>
>>>> I like how C# "fixed" that flaw: every non-empty case must end with a
>>>> break, goto, continue, etc. rather than falling through; to get C's
>>>> fall-through behavior, one must goto the next case label explicitly.
>>>>
>>>> Doing the same in C itself would obviously break _some_ existing code,
>>>> but probably not much; intentional fall-through seems rare in practice.
>>>
>>> Not really:
>>>
>>>      switch (c) {
>>>      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
>>>       ....
>>>      }
>>
>>Same here; I use fallthrough quite often.  20% of my switch
>>statements, maybe?
>
> MISRA Rule 61: 
> Every non-empty case clause in a switch statement shall be terminated
> with a break statement.

Ok. But I'm not bound by their rules.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/27/2015 9:17:20 PM
On Fri, 27 Nov 2015 12:55:03 -0800, Keith Thompson <kst-u@mib.org>
wrote:

>Geoff <geoff@invalid.invalid> writes:
>[...]
>> MISRA Rule 61: 
>> Every non-empty case clause in a switch statement shall be terminated
>> with a break statement.
>
>So much for Duff's device!

Indeed. And if I presented code implementing Duff's device here you
would accuse me of premature optimization. :)
0
Geoff
11/27/2015 9:25:14 PM
On 27-Nov-15 10:08, BartC wrote:
> On 27/11/2015 15:24, Kenny McCormack wrote:
>> As noted originally, and re-inforced since, the key is "non-empty
>> switch statements".
> 
> OK, I missed that...

Nit: it was "non-empty cases".  It'd help if folks didn't snip
_relevant_ parts of the posts they're responding to.

> But I think there's another problem, which is that perhaps C#'s
> switch statements and case labels are properly structured.
> 
> C's aren't, even if most people write use them sensibly. case labels
> can be anywhere within the body of a switch, and it won't always make
> sense to follow them break, continue etc.

The grammar does allow that, but I'm not convinced that's a good thing;
there is a reason every style guide, and convention among nearly all of
those who don't use a style guide, says to only use switches in a very
limited way that doesn't need any of that flexibility.

> That is, if the code following one case label is a nested set of if, 
> for, while, etc, then the next case can appear anywhere in that 
> structure. Example:
> 
> int a,b,c;
> 
> switch (a){
>  if (b==c) {
>     case 10:
>       b=10;
>       if (a==1) {case 20:;}
> 
> }
> }

I can't even figure out what that _does_, and even if I could, it'd fail
a code review anywhere I've ever worked and would probably be rejected
by every OSS project I've ever touched.

Aside from Duff's Device (which I also don't completely understand,
though it's not as bad as the above), I haven't heard of any serious
real-world use of such constructions.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/28/2015 7:20:36 AM
On 27-Nov-15 09:37, supercat@casperkitty.com wrote:
> Stephen Sprunk wrote:
>> On 26-Nov-15 16:24, supercat wrote:
>>>    void foo(int * restrict p);
>>>    void bar(void);
>>>    int test(void)
>>>    {
>>>      int x;
>>>      foo(&x);
>>>      x++;
>>>      bar();
>>>      return x;
>>>    }
>>>
>>> the restrict qualifier on "foo" would allow a compiler to safely
>>> keep x in a register across the call to bar() since there would
>>> be no way bar() could possibly modify x.
>> 
>> Incorrect.  The restriction applies within the block containing a 
>> restricted pointer, which in this case is only foo().  The
>> restriction does _not_ somehow escape foo() and infect x within all
>> of test().
> 
> The restriction says nothing about what "test" may do with x, but if
> foo() were copy the passed-in address somewhere before it returned,
> that copy would be bound to the restrict-qualified parameter and
> would become invalid once that parameter left scope (i.e. after "foo"
> returned).

Also incorrect.

When p goes out of scope, the restriction on p ends, but a pointer
derived from p does not magically become "invalid".

> There would thus be no possibility of "bar" using it.  Since there
> is no other way in which "bar" could acquire the address of x, it
> is thus impossible for bar() to access it.

Actually, foo() _could_ have smuggled a copy of p into static storage
that bar() could read from, and when foo() ended, that pointer would
become an _unrestricted_ alias of x and prevent the compiler doing the
reordering you propose.  In fact, the compiler _must_ assume that this
aliasing does indeed exist unless it can prove otherwise.

If you can't get "restrict"'s semantics right, as its only proponent in
the quarter-century that it has existed, then I think that proves the
usefulness of strict aliasing as an alternative.

>>> (at present, it's legal to take the address of a variable within
>>> a union, but it doesn't seem to be legal to do much with it).
>> 
>> Taking the address of one union member is fine, and accessing it
>> is fine; the problems come when doing that with  _multiple_
>> members.
> 
> I could see reading the Standard in such a way that it was legal to
> take the address of multiple union members and use them in arbitrary
> sequence without restriction. 

I don't.

> I could also see a reading of the Standard in which it is illegal to
> use a pointer of union-member type to access the union at all.

If that were the intent, then the Standard would have prohibited taking
the address of a union member at all and made the question moot.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/28/2015 7:38:49 AM
On Fri, 2015-11-27, BartC wrote:
> On 27/11/2015 15:24, Kenny McCormack wrote:
>> In article <slrnn5gou5.5q5.grahn+nntp@frailea.sa.invalid>,
>> Jorgen Grahn  <grahn+nntp@snipabacken.se> wrote:
>> ...
>>>>> Doing the same in C itself would obviously break _some_ existing code,
>>>>> but probably not much; intentional fall-through seems rare in practice.
>>>>
>>>> Not really:
>>>>
>>>>       switch (c) {
>>>>       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
>>>>        ....
>>>>       }
>>>
>>> Same here; I use fallthrough quite often.  20% of my switch
>>> statements, maybe?
>>
>> As noted originally, and re-inforced since, the key is "non-empty switch
>> statements".
>
> OK, I missed that...

And so did I.  But noone expects Usenet posters to be able to read,
right?

I try to exploit

>>        case 'A':
>> 	/* Special code only for A */
>>        case 'B':
>> 	/* Code for A or B */

but
(a) it very rarely makes the code better 
(b) if it does, I will definitely add a /* FALLTHROUGH */

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/28/2015 8:54:45 AM
On Saturday, November 28, 2015 at 7:20:47 AM UTC, Stephen Sprunk wrote:
> 
> I can't even figure out what that _does_, and even if I could, it'd fail
> a code review anywhere I've ever worked and would probably be rejected
> by every OSS project I've ever touched.
> 
> Aside from Duff's Device (which I also don't completely understand,
> though it's not as bad as the above), I haven't heard of any serious
> real-world use of such constructions.
> 
Here's an example, from my own code

/*
  converts a UTF-8 string into a unicode code point
*/
int bbx_utf8_getch(const char *utf8)
{
    int ch;
    int nb;

    nb = trailingBytesForUTF8[(unsigned char)*utf8];
    ch = 0;
    switch (nb) 
    {
            /* these fall through deliberately */
        case 3: ch += (unsigned char)*utf8++; ch <<= 6;
        case 2: ch += (unsigned char)*utf8++; ch <<= 6;
        case 1: ch += (unsigned char)*utf8++; ch <<= 6;
        case 0: ch += (unsigned char)*utf8++;
    }
    ch -= offsetsFromUTF8[nb];
    
    return ch;
} 

I don't know if the function can be written more efficiently without
the switch fall-through.
0
Malcolm
11/28/2015 10:24:20 AM
In article <n3bkfk$rj5$1@dont-email.me>,
Stephen Sprunk  <stephen@sprunk.org> wrote:
....
>> int a,b,c;
>> 
>> switch (a){
>>  if (b==c) {
>>     case 10:
>>       b=10;
>>       if (a==1) {case 20:;}
>> 
>> }
>> }
>
>I can't even figure out what that _does_, ...

I think that switch() has to be defined as just a bunch of goto-s - note
that it doesn't have to be implemented like that, but it has to behave as
if it were.  That is, the above behaves the same as:

 if (a == 10) goto case_10
 if (a == 20) goto case_20
  if (b==c) {
     case_10:
       b=10;
       if (a==1) {case_20:;}

which is legal, although ugly, C code.

It does raise an interesting question, though.  What if the thing right
after the opening { in a switch statement isn't the word "case"?  I.e.,
something like:

switch (a) {
if (b == c)

>Aside from Duff's Device (which I also don't completely understand,
>though it's not as bad as the above), I haven't heard of any serious
>real-world use of such constructions.

I suppose it depends on what your definition of "real-world" is.

BTW, Malcolm's followup shows a "real-world" use of fallthrough but not an
example of this sort of blatant mis-use of switch().  I.e., Malcolm's use
case doesn't really address the issue here.  Note that use of fallthrough,
although not common (and, apparently, banned by some coding rules), is not
entirely rare or unheard of in the "real world".

-- 
"They shall be attended by boys graced with eternal youth, who to the
beholder?s eyes will seem like sprinkled pearls.  When you gaze  upon that
scene, you will behold a kingdom blissful and glorious."

--- Qur'an 76:19 ---
0
gazelle
11/28/2015 12:43:13 PM
On 28/11/2015 07:20, Stephen Sprunk wrote:
> On 27-Nov-15 10:08, BartC wrote:

>> But I think there's another problem, which is that perhaps C#'s
>> switch statements and case labels are properly structured.
>>
>> C's aren't, even if most people write use them sensibly.

> The grammar does allow that, but I'm not convinced that's a good thing;
> there is a reason every style guide, and convention among nearly all of
> those who don't use a style guide, says to only use switches in a very
> limited way that doesn't need any of that flexibility.

It's not a good thing. It's one of those crude remnants of C's original 
design that we're now lumbered with and which makes it harder to change.

(The most useful thing to do at the end of a case branch is to pass 
control to the end of the switch statement. Exactly as happens with if 
or else branches. But even C# requires an explicit break. It should have 
been implicit, which it could have been with a brand new language.)

-- 
Bartc
0
BartC
11/28/2015 2:33:31 PM
Geoff <geoff@invalid.invalid> writes:

> On Fri, 27 Nov 2015 12:55:03 -0800, Keith Thompson <kst-u@mib.org>
> wrote:
>
>> Geoff <geoff@invalid.invalid> writes:
>> [...]
>>> MISRA Rule 61: 
>>> Every non-empty case clause in a switch statement shall be
>>> terminated with a break statement.
>>
>> So much for Duff's device!
>
> Indeed.  And if I presented code implementing Duff's device here
> you would accuse me of premature optimization. :)

It's interesting you should say that, as just the other day I had
occasion to use a Duff's-device-like construct in some code I was
refactoring.  And indeed what prompted the revision was meeting a
performance goal.  Here is an excerpt:

    #define HANDLE_CASE(n) ...
        // macro body includes conditional return's

    switch( k & 7 ){
        while(1){
            case 0:   HANDLE_CASE( 0 );
            case 2:   HANDLE_CASE( 2 );
            case 4:   HANDLE_CASE( 4 );
            case 6:   HANDLE_CASE( 6 );
        }                            
                                     
        while(1){                    
            case 1:   HANDLE_CASE( 1 );
            case 3:   HANDLE_CASE( 3 );
            case 5:   HANDLE_CASE( 5 );
            case 7:   HANDLE_CASE( 7 );
        }
    }

    #undef HANDLE_CASE

Not offering any conclusion, I just thought y'all might find it
interesting.
0
Tim
11/28/2015 3:16:17 PM
On 28/11/15 08:20, Stephen Sprunk wrote:

> I can't even figure out what that _does_, and even if I could, it'd fail
> a code review anywhere I've ever worked and would probably be rejected
> by every OSS project I've ever touched.
>
> Aside from Duff's Device (which I also don't completely understand,
> though it's not as bad as the above), I haven't heard of any serious
> real-world use of such constructions.
>

I have seen a couple of serious uses for such switches, to implement 
co-routines or light-weight threading in C - especially for very small 
systems.

<http://dunkels.com/adam/pt/expansion.html>


0
David
11/28/2015 3:38:35 PM
On 28/11/15 11:24, Malcolm McLean wrote:
> On Saturday, November 28, 2015 at 7:20:47 AM UTC, Stephen Sprunk wrote:
>>
>> I can't even figure out what that _does_, and even if I could, it'd fail
>> a code review anywhere I've ever worked and would probably be rejected
>> by every OSS project I've ever touched.
>>
>> Aside from Duff's Device (which I also don't completely understand,
>> though it's not as bad as the above), I haven't heard of any serious
>> real-world use of such constructions.
>>
> Here's an example, from my own code
>
> /*
>    converts a UTF-8 string into a unicode code point
> */
> int bbx_utf8_getch(const char *utf8)
> {
>      int ch;
>      int nb;
>
>      nb = trailingBytesForUTF8[(unsigned char)*utf8];
>      ch = 0;
>      switch (nb)
>      {
>              /* these fall through deliberately */
>          case 3: ch += (unsigned char)*utf8++; ch <<= 6;
>          case 2: ch += (unsigned char)*utf8++; ch <<= 6;
>          case 1: ch += (unsigned char)*utf8++; ch <<= 6;
>          case 0: ch += (unsigned char)*utf8++;
>      }
>      ch -= offsetsFromUTF8[nb];
>
>      return ch;
> }
>
> I don't know if the function can be written more efficiently without
> the switch fall-through.
>

Of course it can be written just as efficiently without fall-through.

switch (nb)
{
	case 3:
		ch += (unsigned char)*utf8++; ch <<= 6;
		ch += (unsigned char)*utf8++; ch <<= 6;
		ch += (unsigned char)*utf8++; ch <<= 6;
		ch += (unsigned char)*utf8++;
		break;
         case 2:
		ch += (unsigned char)*utf8++; ch <<= 6;
		ch += (unsigned char)*utf8++; ch <<= 6;
		ch += (unsigned char)*utf8++;
		break;
         case 1:
		ch += (unsigned char)*utf8++; ch <<= 6;
		ch += (unsigned char)*utf8++;
		break;
         case 0:
		ch += (unsigned char)*utf8++;
		break;
}

Or perhaps:

	if (nb) {
		for (int i = 0; i < (nb - 1); i++) {
			ch += (unsigned char)*utf8++; ch <<= 6;
		}
	}
	ch += (unsigned char)*utf8++;


Why would you think that your first version is the most efficient? 
Depending on details of the compiler, optimisations, cpus, cache 
effects, inlining, number of registers available, instruction 
scheduling, and a dozen other effects, the other versions may generate 
exactly the same code, or they may generate code that is bigger, 
smaller, faster or slower than the first version.

Premature optimisation is the root of all evil!


Now, if you want to claim that your version is the neatest and clearest 
in the source code, that's a different matter entirely, and you'll have 
better luck there.



0
David
11/28/2015 4:03:51 PM
David Brown <david.brown@hesbynett.no> wrote:
> On 28/11/15 11:24, Malcolm McLean wrote:

(snip on switch fall-through)

>> Here's an example, from my own code

>> /*
>>    converts a UTF-8 string into a unicode code point
>> */
>> int bbx_utf8_getch(const char *utf8)
>> {
>>      int ch;
>>      int nb;
>>
>>      nb = trailingBytesForUTF8[(unsigned char)*utf8];
>>      ch = 0;
>>      switch (nb)
>>      {
>>              /* these fall through deliberately */
>>          case 3: ch += (unsigned char)*utf8++; ch <<= 6;
>>          case 2: ch += (unsigned char)*utf8++; ch <<= 6;
>>          case 1: ch += (unsigned char)*utf8++; ch <<= 6;
>>          case 0: ch += (unsigned char)*utf8++;
>>      }
>>      ch -= offsetsFromUTF8[nb];
>>
>>      return ch;
>> }

>> I don't know if the function can be written more efficiently without
>> the switch fall-through.

> Of course it can be written just as efficiently without fall-through.

It depends on if you mean execution efficiency or written lines
efficiency. 

While the former is often discussed, sometimes the latter is meant.

(snip of expanded switch/case statement)

Also, in any case where lines are duplicated, one has to be
careful when modifying them that all are consistently modified.
The preprocessor can help with that.

-- glen
0
glen
11/28/2015 5:18:36 PM
On 28/11/15 18:18, glen herrmannsfeldt wrote:
> David Brown <david.brown@hesbynett.no> wrote:
>> On 28/11/15 11:24, Malcolm McLean wrote:

>>> I don't know if the function can be written more efficiently without
>>> the switch fall-through.
>
>> Of course it can be written just as efficiently without fall-through.
>
> It depends on if you mean execution efficiency or written lines
> efficiency.
>
> While the former is often discussed, sometimes the latter is meant.

I agree entirely (you snipped the bit where I mentioned efficient source 
code).

>
> (snip of expanded switch/case statement)
>
> Also, in any case where lines are duplicated, one has to be
> careful when modifying them that all are consistently modified.

Yes, that's the danger.  Copy-and-paste works fine once, but maintenance 
quickly becomes an error-prone chore.

> The preprocessor can help with that.
>

I would rather say that separating off static inline functions can help 
with that, but occasionally macros are the best choice.


0
David
11/28/2015 5:41:06 PM
On Saturday, November 28, 2015 at 4:04:10 PM UTC, David Brown wrote:
> On 28/11/15 11:24, Malcolm McLean wrote:
> > On Saturday, November 28, 2015 at 7:20:47 AM UTC, Stephen Sprunk wrote:
> >>
> >> I can't even figure out what that _does_, and even if I could, it'd fail
> >> a code review anywhere I've ever worked and would probably be rejected
> >> by every OSS project I've ever touched.
> >>
> >> Aside from Duff's Device (which I also don't completely understand,
> >> though it's not as bad as the above), I haven't heard of any serious
> >> real-world use of such constructions.
> >>
> > Here's an example, from my own code
> >
> > /*
> >    converts a UTF-8 string into a unicode code point
> > */
> > int bbx_utf8_getch(const char *utf8)
> > {
> >      int ch;
> >      int nb;
> >
> >      nb = trailingBytesForUTF8[(unsigned char)*utf8];
> >      ch = 0;
> >      switch (nb)
> >      {
> >              /* these fall through deliberately */
> >          case 3: ch += (unsigned char)*utf8++; ch <<= 6;
> >          case 2: ch += (unsigned char)*utf8++; ch <<= 6;
> >          case 1: ch += (unsigned char)*utf8++; ch <<= 6;
> >          case 0: ch += (unsigned char)*utf8++;
> >      }
> >      ch -= offsetsFromUTF8[nb];
> >
> >      return ch;
> > }
> >
> > I don't know if the function can be written more efficiently without
> > the switch fall-through.
> >
> 
> Of course it can be written just as efficiently without fall-through.
> 
> switch (nb)
> {
> 	case 3:
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++;
> 		break;
>          case 2:
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++;
> 		break;
>          case 1:
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++;
> 		break;
>          case 0:
> 		ch += (unsigned char)*utf8++;
> 		break;
> }
> 
> Or perhaps:
> 
> 	if (nb) {
> 		for (int i = 0; i < (nb - 1); i++) {
> 			ch += (unsigned char)*utf8++; ch <<= 6;
> 		}
> 	}
> 	ch += (unsigned char)*utf8++;
> 
> 
> Why would you think that your first version is the most efficient? 
> Depending on details of the compiler, optimisations, cpus, cache 
> effects, inlining, number of registers available, instruction 
> scheduling, and a dozen other effects, the other versions may generate 
> exactly the same code, or they may generate code that is bigger, 
> smaller, faster or slower than the first version.
> 
> Premature optimisation is the root of all evil!
> 
> 
> Now, if you want to claim that your version is the neatest and clearest 
> in the source code, that's a different matter entirely, and you'll have 
> better luck there.>
>
Your version compiles (on a naive compiler) to

take nb
jump to label
execute block
jump to end of block
fiddle
return

mine compiles to

take nb
jump to label
execute block
fiddle
return

Admittedly you can get round that by moving the fiddle /return into 
the switched block.

Secondly, more compact code tends to execute a bit faster due to 
clever pipeling and memory management (so the looped version
might actually be faster on many CPUs).



0
Malcolm
11/28/2015 5:42:29 PM
On 28-Nov-15 04:24, Malcolm McLean wrote:
> Stephen Sprunk wrote:
>> I can't even figure out what that _does_, and even if I could,
>> it'd fail a code review anywhere I've ever worked and would
>> probably be rejected by every OSS project I've ever touched.
>> 
>> Aside from Duff's Device (which I also don't completely
>> understand, though it's not as bad as the above), I haven't heard
>> of any serious real-world use of such constructions.
> 
> Here's an example, from my own code
> ... 
> I don't know if the function can be written more efficiently without
> the switch fall-through.

That's simple fall-through, which was not the issue at hand.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/28/2015 6:41:49 PM
On 28-Nov-15 06:43, Kenny McCormack wrote:
> In article <n3bkfk$rj5$1@dont-email.me>,
> Stephen Sprunk  <stephen@sprunk.org> wrote:
> ....
>>> int a,b,c;
>>>
>>> switch (a){
>>>  if (b==c) {
>>>     case 10:
>>>       b=10;
>>>       if (a==1) {case 20:;}
>>>
>>> }
>>> }
>>
>> I can't even figure out what that _does_, ...
> 
> I think that switch() has to be defined as just a bunch of goto-s -
> note that it doesn't have to be implemented like that, but it has to
> behave as if it were.  That is, the above behaves the same as:
> 
>  if (a == 10) goto case_10
>  if (a == 20) goto case_20
>   if (b==c) {
>      case_10:
>        b=10;
>        if (a==1) {case_20:;}
> 
> which is legal, although ugly, C code.

Indeed, though IMHO that should fail any code review and I have no
objection to banning such from the language.  If you want ugly,
goto-infested code, then at least write it explicitly.

> It does raise an interesting question, though.  What if the thing right
> after the opening { in a switch statement isn't the word "case"?  I.e.,
> something like:
> 
> switch (a) {
> if (b == c)

My guess is that it depends on whether there is a default case; if so,
then I'd expect such code to be moot.

>> Aside from Duff's Device (which I also don't completely understand,
>> though it's not as bad as the above), I haven't heard of any serious
>> real-world use of such constructions.
> 
> I suppose it depends on what your definition of "real-world" is.

I've never seen it in real code used in real projects.  I'm told that
Duff's Device is (or at least was) actually used somewhere, but I have
never run into it.

> BTW, Malcolm's followup shows a "real-world" use of fallthrough but
> not an example of this sort of blatant mis-use of switch().  I.e.,
> Malcolm's use case doesn't really address the issue here.  Note that
> use of fallthrough, although not common (and, apparently, banned by
> some coding rules), is not entirely rare or unheard of in the "real
> world".

Fall-through is another matter, and I find C#'s answer workable.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/28/2015 7:01:41 PM
On Saturday, November 28, 2015 at 1:39:01 AM UTC-6, Stephen Sprunk wrote:
> When p goes out of scope, the restriction on p ends, but a pointer
> derived from p does not magically become "invalid".

I acknowledged my mistake elsewhere, though I'm curious what if anything is
gained by eliminating the restrictions on the derived pointer when the base
pointer dies?  It significantly impedes what would otherwise be useful
optimizations, and I fail to see any benefit that it would afford a
programmer.

> If you can't get "restrict"'s semantics right, as its only proponent in
> the quarter-century that it has existed, then I think that proves the
> usefulness of strict aliasing as an alternative.

The fact that restrict's semantics were not perfectly designed does not mean
the type-based aliasing rules aren't worse.

Consider something like:

    #include <stdint.h>

    unsigned char *buff;
    uint32_t buff_mask;
    uint32_t buff_ptr;

    int get_next_byte(void) { return buff[buff_mask & buff_ptr++]; }

    void get_data(void * dest, int n)
    {
      unsigned char *p = dest;
      for (int i=0; i<n; i++) p[i] = get_next_byte();
    }

Compare the optimal implementation a compiler would be allowed to produce
for the code as written with the optimal implementation a compiler would
be allowed to produce if "dest" had a restrict qualifier.  GCC doesn't
seem to produce optimal code even in the latter case, but it still cuts
out three loads and a store from the loop.

As another example, given:

#include <stdint.h>

void foo(int * ip, float * fp)
{
  for (int i=0; i<100; i++)
    ip[i] = 1;
  for (int i=0; i<100; i++)
    fp[i] = 1.0;
  
}

Type-based aliasing rules don't give a compiler much freedom with the above
code [since ip and fp could be pointers to overlapping regions of allocated
storage] but adding "restrict" to one or both pointers would allow a compiler to rewrite it as:

#include <stdint.h>

void foo(int * restrict ip, float * restrict fp)
{
  for (int i=0; i<100; i++)
  {
    ip[i] = 1;
    fp[i] = 1.0;
  }
}

which is a pretty big performance win.

Otherwise, I'm hard-pressed to come up with a reading of the Standard which
would allow useful aliasing and justify compiler's behavior when code uses
the addresses of two union members as pointers to their respective types,
but would not forbid using a pointer to even one union member as a pointer
to its type; that would suggest that using the address of even one union
memory or a portion thereof as a pointer to its own (non-character) type
invokes UB and the only reason that code that does such things seems to
"work" is that compilers haven't yet fully exploited their optimization
opportunities.

Worse, since the same "effective type" language is used to discuss the
behaviors of structures and union, unless I'm missing something, there would
be no more justification for allowing something like:

    void get_median_of_5(int *);

    typedef struct { int sensor_id; int readings[5]; } SENSOR;
    SENSOR sens;
    ...
    get_median_of_5(sens.readings);

than allowing such constructs using union members.  From what I can tell,
under the Standard, the proper ways to write such code would either:

(1) Have the "get_median_of_5" method accept a SENSOR* rather than an
    int*, and use a separate such method for every type of structure
    that includes an array of 5 integers and needs to compute the
    median thereof.

(2) Define a structure for the sensor readings and pass it by value.

(3) Have the code within "get_median_of_5" convert passed-in pointers
    to a character type, and use multiple character reads to fetch the
    data for each integer.

For some kinds of code one of those might be workable.  For others, none of
them would be tolerable.  I can't figure out any reading of the rules in C99,
though, that would justify compiler behavior but wouldn't make use of
int* pointers to the readings invoke Undefined Behavior.
0
supercat
11/28/2015 7:41:12 PM
Stephen Sprunk wrote:
> 
> On 28-Nov-15 06:43, Kenny McCormack wrote:
> > In article <n3bkfk$rj5$1@dont-email.me>,
> > Stephen Sprunk  <stephen@sprunk.org> wrote:
> > ....
> >>> int a,b,c;
> >>>
> >>> switch (a){
> >>>  if (b==c) {
> >>>     case 10:
> >>>       b=10;
> >>>       if (a==1) {case 20:;}
> >>>
> >>> }
> >>> }
> >>
> >> I can't even figure out what that _does_, ...
> > 
> > I think that switch() has to be defined as just a bunch of goto-s -
> > note that it doesn't have to be implemented like that, but it has to
> > behave as if it were.  That is, the above behaves the same as:

You missed one goto:

> >  if (a == 10) goto case_10
> >  if (a == 20) goto case_20
     goto case_default
> >   if (b==c) {
> >      case_10:
> >        b=10;
> >        if (a==1) {case_20:;}
      }
     case_default:;

> > which is legal, although ugly, C code.
> 
> Indeed, though IMHO that should fail any code review and I have no
> objection to banning such from the language.  If you want ugly,
> goto-infested code, then at least write it explicitly.
> 
> > It does raise an interesting question, though.  What if the thing right
> > after the opening { in a switch statement isn't the word "case"?  I.e.,
> > something like:
> > 
> > switch (a) {
> > if (b == c)
> 
> My guess is that it depends on whether there is a default case; if so,
> then I'd expect such code to be moot.

No, it doesn't depend on whether there is a default case. In the
example above, where it is an 'if', it is unreachable. If it is
a loop, as in the example below, it might be reachable:

    switch (a) {
        while (b == c) {
            case 10: b = 10;
            if (c == 1) { case 20: c = 10;}
        }
    }

> >> Aside from Duff's Device (which I also don't completely understand,
> >> though it's not as bad as the above), I haven't heard of any serious
> >> real-world use of such constructions.
> >
> > I suppose it depends on what your definition of "real-world" is.
>
> I've never seen it in real code used in real projects.  I'm told that
> Duff's Device is (or at least was) actually used somewhere, but I have
> never run into it.

I think I wrote something like that recently. It wouldn't have been
nearly so incomprehensible as the above, because it was real code
to solve a real problem, rather than something made up. However, by
the time I had finished writing the function, it had been changed
back into a typical switch statement, as the clearest way to express
the code that covered all the cases, so unfortunately I can't find it. 
0
Philip
11/28/2015 8:06:13 PM
David Brown <david.brown@hesbynett.no> writes:

> On 28/11/15 11:24, Malcolm McLean wrote:
>> On Saturday, November 28, 2015 at 7:20:47 AM UTC, Stephen Sprunk wrote:
>>>
>>> I can't even figure out what that _does_, and even if I could, it'd fail
>>> a code review anywhere I've ever worked and would probably be rejected
>>> by every OSS project I've ever touched.
>>>
>>> Aside from Duff's Device (which I also don't completely understand,
>>> though it's not as bad as the above), I haven't heard of any serious
>>> real-world use of such constructions.
>>>
>> Here's an example, from my own code
>>
>> /*
>>    converts a UTF-8 string into a unicode code point
>> */
>> int bbx_utf8_getch(const char *utf8)
>> {
>>      int ch;
>>      int nb;
>>
>>      nb = trailingBytesForUTF8[(unsigned char)*utf8];
>>      ch = 0;
>>      switch (nb)
>>      {
>>              /* these fall through deliberately */
>>          case 3: ch += (unsigned char)*utf8++; ch <<= 6;
>>          case 2: ch += (unsigned char)*utf8++; ch <<= 6;
>>          case 1: ch += (unsigned char)*utf8++; ch <<= 6;
>>          case 0: ch += (unsigned char)*utf8++;
>>      }
>>      ch -= offsetsFromUTF8[nb];
>>
>>      return ch;
>> }
>>
>> I don't know if the function can be written more efficiently without
>> the switch fall-through.
>>
>
> Of course it can be written just as efficiently without fall-through.
>
> switch (nb)
> {
> 	case 3:
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++;
> 		break;
>         case 2:
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++;
> 		break;
>         case 1:
> 		ch += (unsigned char)*utf8++; ch <<= 6;
> 		ch += (unsigned char)*utf8++;
> 		break;
>         case 0:
> 		ch += (unsigned char)*utf8++;
> 		break;
> }

Given the overall structure of the code, there are some other benefits
to writing out the cases like this.  Some jumps can probably be removed
and since offsetsFromUTF8 is just a four int static array, it can be
"inlined" by writing:

     const unsigned char *ucp = utf8;
     switch (trailingBytesForUTF8[*ucp])
     {
     case 3:
          return (((((ucp[0] << 6) + ucp[1]) << 6) + ucp[2]) << 6) + ucp[3]
               - offsetsFromUTF8[3];
     case 2:
          return (((ucp[0] << 6) + ucp[1]) << 6) + ucp[2]
               - offsetsFromUTF8[2];
     case 1:
          return (ucp[0] << 6) + ucp[1]
               - offsetsFromUTF8[1];
     case 0:
          return ucp[0]
               - offsetsFromUTF8[0];
     }

(Of course you could just write the constants in place but this will be
no worse.)

> Or perhaps:
>
> 	if (nb) {
> 		for (int i = 0; i < (nb - 1); i++) {
> 			ch += (unsigned char)*utf8++; ch <<= 6;
> 		}
> 	}
> 	ch += (unsigned char)*utf8++;

And this can be written

     for (int i = 0; i < nb; i++) {
          ch <<= 6;
          ch += (unsigned char)*utf8++;
     }

or even as

     for (int i = 0; i < nb; i++, ch <<= 6)
          ch += (unsigned char)*utf8++;

any of which might be better or worse depending on so many things.

> Why would you think that your first version is the most efficient?
> Depending on details of the compiler, optimisations, cpus, cache
> effects, inlining, number of registers available, instruction
> scheduling, and a dozen other effects, the other versions may generate
> exactly the same code, or they may generate code that is bigger,
> smaller, faster or slower than the first version.

But also it's important to keep in mind that it might not matter.  In
that case, clarity is king, which raises this question of yours:

<snip>
> Now, if you want to claim that your version is the neatest and
> clearest in the source code, that's a different matter entirely, and
> you'll have better luck there.

I don't know which one is clearest.

-- 
Ben.
0
Ben
11/28/2015 10:39:29 PM
On 29-Nov-15 09:51, Kenny McCormack wrote:
> Nowadays, things have changed, giving rise to the snarky "advice" you
> see on this forum all the time about letting the compiler do the
> optimization, not you.

"Snarky" has a negative connotation that I don't think applies when
people here give such advice.  Well, at least it doesn't when I do so;
I'm trying to help people avoid wasted and often counter-productive effort.

> But the point is that that this frequently given snarky "advice" was
> not appropriate in the days of naive compilers.

Of course not, but we aren't giving such advice through a time portal;
it's said in modern times to users of modern compilers.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/29/2015 1:01:01 AM
On 28-Nov-15 14:06, Philip Lantz wrote:
> Stephen Sprunk wrote:
>> On 28-Nov-15 06:43, Kenny McCormack wrote:
>>> It does raise an interesting question, though.  What if the thing
>>> right after the opening { in a switch statement isn't the word
>>> "case"?  I.e., something like:
>>>
>>> switch (a) {
>>> if (b == c)
>>
>> My guess is that it depends on whether there is a default case; if so,
>> then I'd expect such code to be moot.
> 
> No, it doesn't depend on whether there is a default case. In the
> example above, where it is an 'if', it is unreachable. If it is
> a loop, as in the example below, it might be reachable:

Ah, okay; that makes sense.

>>>> Aside from Duff's Device (which I also don't completely
>>>> understand, though it's not as bad as the above), I haven't
>>>> heard of any serious real-world use of such constructions.
>>>
>>> I suppose it depends on what your definition of "real-world" is.
>> 
>> I've never seen it in real code used in real projects.  I'm told
>> that Duff's Device is (or at least was) actually used somewhere,
>> but I have never run into it.
> 
> I think I wrote something like that recently. It wouldn't have been 
> nearly so incomprehensible as the above, because it was real code to
> solve a real problem, rather than something made up. However, by the
> time I had finished writing the function, it had been changed back
> into a typical switch statement, as the clearest way to express the
> code that covered all the cases, so unfortunately I can't find it.

Interestingly, the Wikipedia article claims that _removing_ Duff's
Device turned out to have made XFree86 Server 4.0 both smaller and
faster, presumably because it defeated other compiler optimizations.
So, I'm not sure there's any remaining argument for such code.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/29/2015 1:03:39 AM
On 29/11/15 01:03, Stephen Sprunk wrote:

<snip>

> Interestingly, the Wikipedia article claims that _removing_ Duff's
> Device turned out to have made XFree86 Server 4.0 both smaller and
> faster, presumably because it defeated other compiler optimizations.
> So, I'm not sure there's any remaining argument for such code.

It is, at the very least, an intriguing curio, and it may even have a 
place as an interview question.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
11/29/2015 1:10:37 AM
On Saturday, November 28, 2015 at 7:03:54 PM UTC-6, Stephen Sprunk wrote:
> Interestingly, the Wikipedia article claims that _removing_ Duff's
> Device turned out to have made XFree86 Server 4.0 both smaller and
> faster, presumably because it defeated other compiler optimizations.
> So, I'm not sure there's any remaining argument for such code.

On some implementations such tricks may improve performance.  On others, they
won't.  Personally, I think that if it's possible to convince a C compiler to
produce optimal machine code, even if the C code needs to be a little weird, that may be better than using assembly language if there's a way of convincing other compilers to produce machine code that is at least correct even if not terribly efficient.
0
supercat
11/29/2015 4:30:44 AM
On 28/11/15 18:42, Malcolm McLean wrote:
> On Saturday, November 28, 2015 at 4:04:10 PM UTC, David Brown wrote:
>> On 28/11/15 11:24, Malcolm McLean wrote:

>>
>> Why would you think that your first version is the most efficient? 
>> Depending on details of the compiler, optimisations, cpus, cache 
>> effects, inlining, number of registers available, instruction 
>> scheduling, and a dozen other effects, the other versions may generate 
>> exactly the same code, or they may generate code that is bigger, 
>> smaller, faster or slower than the first version.
>>
>> Premature optimisation is the root of all evil!
>>
>>
>> Now, if you want to claim that your version is the neatest and clearest 
>> in the source code, that's a different matter entirely, and you'll have 
>> better luck there.>
>>
> Your version compiles (on a naive compiler) to

Why would you want to compare speed or efficiency (of object code) on a
"na�ve compiler" ?  You would want to compare it on the best
optimisation you can get from the compiler.

> 
> take nb
> jump to label
> execute block
> jump to end of block
> fiddle
> return
> 
> mine compiles to
> 
> take nb
> jump to label
> execute block
> fiddle
> return
> 
> Admittedly you can get round that by moving the fiddle /return into 
> the switched block.
> 
> Secondly, more compact code tends to execute a bit faster due to 
> clever pipeling and memory management (so the looped version
> might actually be faster on many CPUs).
> 

Getting fast (or small) code is a cooperation between the programmer and
the compiler, combined with lots of testing and profiling on relevant
targets.  Then you would know, for example, that "jump to the end of
block" is often a zero-cost operation - unconditional branches or
correctly predicted branches can be handled early in the pipeline on
modern cpus, and do not delay the instruction scheme.  But you might
also find that cache issues, instruction pre-fetch buffers, and other
variations mean that one variant of the code will work measurably faster
on some systems and measurably slower on others.

In general, you should write the clearest, simplest, and most
maintainable source code that could be expected to generate efficient
object code - and let the compiler handle the details.  Only on very
rare occasions does it make sense to aim for the absolute fastest object
code - especially as most people who do that, get it wrong.  (They write
stuff in assembly and thus limit the compiler from optimising around the
code, or they write something that works fast on their development PC's
cpu but is slower on end-users cpu, or they spend so much time on the
details that they miss the big algorithmic improvements.)

And as noted, the switch with fall-throughs is arguably one of the
clearest, simplest and most maintainable methods in this case - /if/ the
fall-through is clearly documented, and allowed by any relevant coding
standards and practices.  My point is merely that it is far from sure
that it is the most efficient method.


0
David
11/29/2015 12:00:20 PM
On 28/11/15 23:39, Ben Bacarisse wrote:
> David Brown <david.brown@hesbynett.no> writes:
> 
>> On 28/11/15 11:24, Malcolm McLean wrote:
>>> On Saturday, November 28, 2015 at 7:20:47 AM UTC, Stephen Sprunk wrote:
>>>>
>>>> I can't even figure out what that _does_, and even if I could, it'd fail
>>>> a code review anywhere I've ever worked and would probably be rejected
>>>> by every OSS project I've ever touched.
>>>>
>>>> Aside from Duff's Device (which I also don't completely understand,
>>>> though it's not as bad as the above), I haven't heard of any serious
>>>> real-world use of such constructions.
>>>>
>>> Here's an example, from my own code
>>>
>>> /*
>>>    converts a UTF-8 string into a unicode code point
>>> */
>>> int bbx_utf8_getch(const char *utf8)
>>> {
>>>      int ch;
>>>      int nb;
>>>
>>>      nb = trailingBytesForUTF8[(unsigned char)*utf8];
>>>      ch = 0;
>>>      switch (nb)
>>>      {
>>>              /* these fall through deliberately */
>>>          case 3: ch += (unsigned char)*utf8++; ch <<= 6;
>>>          case 2: ch += (unsigned char)*utf8++; ch <<= 6;
>>>          case 1: ch += (unsigned char)*utf8++; ch <<= 6;
>>>          case 0: ch += (unsigned char)*utf8++;
>>>      }
>>>      ch -= offsetsFromUTF8[nb];
>>>
>>>      return ch;
>>> }
>>>
>>> I don't know if the function can be written more efficiently without
>>> the switch fall-through.
>>>
>>
>> Of course it can be written just as efficiently without fall-through.
>>
>> switch (nb)
>> {
>> 	case 3:
>> 		ch += (unsigned char)*utf8++; ch <<= 6;
>> 		ch += (unsigned char)*utf8++; ch <<= 6;
>> 		ch += (unsigned char)*utf8++; ch <<= 6;
>> 		ch += (unsigned char)*utf8++;
>> 		break;
>>         case 2:
>> 		ch += (unsigned char)*utf8++; ch <<= 6;
>> 		ch += (unsigned char)*utf8++; ch <<= 6;
>> 		ch += (unsigned char)*utf8++;
>> 		break;
>>         case 1:
>> 		ch += (unsigned char)*utf8++; ch <<= 6;
>> 		ch += (unsigned char)*utf8++;
>> 		break;
>>         case 0:
>> 		ch += (unsigned char)*utf8++;
>> 		break;
>> }
> 

Note that the compiler could, in theory, see that this version is the
same as the original version.

> Given the overall structure of the code, there are some other benefits
> to writing out the cases like this.  Some jumps can probably be removed
> and since offsetsFromUTF8 is just a four int static array, it can be
> "inlined" by writing:
> 
>      const unsigned char *ucp = utf8;
>      switch (trailingBytesForUTF8[*ucp])
>      {
>      case 3:
>           return (((((ucp[0] << 6) + ucp[1]) << 6) + ucp[2]) << 6) + ucp[3]
>                - offsetsFromUTF8[3];
>      case 2:
>           return (((ucp[0] << 6) + ucp[1]) << 6) + ucp[2]
>                - offsetsFromUTF8[2];
>      case 1:
>           return (ucp[0] << 6) + ucp[1]
>                - offsetsFromUTF8[1];
>      case 0:
>           return ucp[0]
>                - offsetsFromUTF8[0];
>      }
> 
> (Of course you could just write the constants in place but this will be
> no worse.)

In my brief testing, my compiler generated code much like a "direct
translation" of that structure.  In particular, when a cpu has plenty of
registers it makes sense to collect the data early into a number of
registers, and then do the calculations in order to hide read latencies
and maximise instruction overlap.

> 
>> Or perhaps:
>>
>> 	if (nb) {
>> 		for (int i = 0; i < (nb - 1); i++) {
>> 			ch += (unsigned char)*utf8++; ch <<= 6;
>> 		}
>> 	}
>> 	ch += (unsigned char)*utf8++;
> 
> And this can be written
> 
>      for (int i = 0; i < nb; i++) {
>           ch <<= 6;
>           ch += (unsigned char)*utf8++;
>      }
> 

That is a little neater, IMHO.

> or even as
> 
>      for (int i = 0; i < nb; i++, ch <<= 6)
>           ch += (unsigned char)*utf8++;
> 
> any of which might be better or worse depending on so many things.

I never like using the comma operator.  But as you say, it could be
better or worse depending on many things, including how you define
"better" and "worse".

> 
>> Why would you think that your first version is the most efficient?
>> Depending on details of the compiler, optimisations, cpus, cache
>> effects, inlining, number of registers available, instruction
>> scheduling, and a dozen other effects, the other versions may generate
>> exactly the same code, or they may generate code that is bigger,
>> smaller, faster or slower than the first version.
> 
> But also it's important to keep in mind that it might not matter.  In
> that case, clarity is king, which raises this question of yours:
> 
> <snip>
>> Now, if you want to claim that your version is the neatest and
>> clearest in the source code, that's a different matter entirely, and
>> you'll have better luck there.
> 
> I don't know which one is clearest.
> 

And I'm sure the posters in this thread would have a variety of opinions
as to why one version is clearer than all the others.  So it's best not
to go there.  Despite that, we can probably all agree that clarity is
the most important driving force here :-)


0
David
11/29/2015 12:11:23 PM
On Sunday, November 29, 2015 at 12:00:34 PM UTC, David Brown wrote:
> On 28/11/15 18:42, Malcolm McLean wrote:
>
> > Your version compiles (on a naive compiler) to
>=20
> Why would you want to compare speed or efficiency (of object code) on a
> "na=C4=ABve compiler" ?  You would want to compare it on the best
> optimisation you can get from the compiler.
>=20
If you know your target platform, the of course you profile, or base the co=
de on how
you know the target works.
But if you don't, the best strategy is to make the optimisation as easy as =
possible
for a naive compiler. Then you ought to get the optimal result. Of course i=
t's sometimes
impossible, as I said, the looped version may actually execute faster on a =
Pentium
because the loop handling is now so good, even though it's inherently doing=
 more
calculations. There's a point at which you have to give up.
0
Malcolm
11/29/2015 1:11:52 PM
On Sun, 2015-11-29, Stephen Sprunk wrote:
....
> Interestingly, the Wikipedia article claims that _removing_ Duff's
> Device turned out to have made XFree86 Server 4.0 both smaller and
> faster, presumably because it defeated other compiler optimizations.
> So, I'm not sure there's any remaining argument for such code.

Didn't Duff himself note that his Device would soon be defeated by
optimizers?  I'm too lazy to check, but I seem to recall that was one
of the plot twists, so to speak.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/29/2015 3:24:35 PM
On Sun, 2015-11-29, David Brown wrote:
....
> In general, you should write the clearest, simplest, and most
> maintainable source code that could be expected to generate efficient
> object code - and let the compiler handle the details.

Yes.  I worry about efficiency, but I stop when I'm convinced I've
given the compiler enough information so it /can/ optimize.  That
includes enabling inlining, and not trying to be too clever with
casts.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/29/2015 3:35:47 PM
On Sun, 2015-11-29, Malcolm McLean wrote:
> On Sunday, November 29, 2015 at 12:00:34 PM UTC, David Brown wrote:
>> On 28/11/15 18:42, Malcolm McLean wrote:
>>
>> > Your version compiles (on a naive compiler) to
>> 
>> Why would you want to compare speed or efficiency (of object code) on a
>> "naive compiler" ?  You would want to compare it on the best
>> optimisation you can get from the compiler.
>> 

> If you know your target platform, the of course you profile, or base
> the code on how you know the target works.  But if you don't, the
> best strategy is to make the optimisation as easy as possible for a
> naive compiler. Then you ought to get the optimal result.

But there are no naive compilers today!  And few CPUs that look like
e.g. the MC68000 once did, if I understand correctly.

Writing your code as if it's to be compiled for an obsolete CPU using
a non-optimizing compiler is IMO a waste of energy.  You can get more
readable code by not doing it -- and probably free up time for doing
more worthwhile optimizations, too.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/29/2015 3:47:06 PM
In article <slrnn5m65i.5q5.grahn+nntp@frailea.sa.invalid>,
Jorgen Grahn  <grahn+nntp@snipabacken.se> wrote:
>On Sun, 2015-11-29, Stephen Sprunk wrote:
>...
>> Interestingly, the Wikipedia article claims that _removing_ Duff's
>> Device turned out to have made XFree86 Server 4.0 both smaller and
>> faster, presumably because it defeated other compiler optimizations.
>> So, I'm not sure there's any remaining argument for such code.
>
>Didn't Duff himself note that his Device would soon be defeated by
>optimizers?  I'm too lazy to check, but I seem to recall that was one
>of the plot twists, so to speak.

Indeed.  A couple of points that address various issues brought up in this
thread:

    1) Duff invented this a long time ago, in the 80s if not the 70s, and
	in those days, compilers were very naive.  If you wanted efficient
	code, you had to write it to be so.  Nowadays, things have changed,
	giving rise to the snarky "advice" you see on this forum all the
	time about letting the compiler do the optimization, not you.  But
	the point is that that this frequently given snarky "advice" was
	not appropriate in the days of naive compilers.

    2) Just as a point of trivia, Duff was working for a film studio at the
	time.  Might even have been LucasFilm, but I'd have to check that.

-- 
BigBusiness types (aka,
    Republicans/Conservatives/Independents/Liberatarians/whatevers)
don't hate big government.  They *love* big government as a means for
them to get rich, sucking off the public teat.  What they don't like is
*democracy* - little people actually having the right to vote and stuff
like that.

0
gazelle
11/29/2015 3:51:29 PM
Jorgen Grahn <grahn+nntp@snipabacken.se> wrote:

> On Sun, 2015-11-29, Malcolm McLean wrote:
> > On Sunday, November 29, 2015 at 12:00:34 PM UTC, David Brown wrote:
> >> On 28/11/15 18:42, Malcolm McLean wrote:
> >>
> >> > Your version compiles (on a naive compiler) to
> >> 
> >> Why would you want to compare speed or efficiency (of object code) on a
> >> "naive compiler" ?  You would want to compare it on the best
> >> optimisation you can get from the compiler.
> 
> > If you know your target platform, the of course you profile, or base
> > the code on how you know the target works.  But if you don't, the
> > best strategy is to make the optimisation as easy as possible for a
> > naive compiler. Then you ought to get the optimal result.
> 
> But there are no naive compilers today!  And few CPUs that look like
> e.g. the MC68000 once did, if I understand correctly.

However, there are compilers (and CPUs) that are non-naive in different
ways, so unless you know your exact target and also know that this will
_never_ change, premature optimisation is still unwise.

Richard
0
raltbos
11/29/2015 6:49:11 PM
On Sunday, November 29, 2015 at 9:47:25 AM UTC-6, Jorgen Grahn wrote:
> But there are no naive compilers today!  And few CPUs that look like
> e.g. the MC68000 once did, if I understand correctly.

That depends on the application field.  The Cortex-M0 is a relatively new
version of the ARM which is popular in low-power embedded applications; while
it's faster than the 68000 (not sure how it compares with later ColdFire
processors for speed) and includes a 32x32 multiply and fast shifter (the
68000 had a 16x16 multiply and an iterative shifter), in many other regards
the 68000 was the more powerful machine [the full ARM instruction set is
more powerful than that of the 68000, but the Cortex-M0 is limited to a
small subset of the ARM instruction set].  While the Cortex-M0 is intruding
into their territory, 8-bit processors have also been used for many kinds of
small embedded systems and can handle a reasonable dialect of C.

For systems programming, it's very useful to have a language which uses
operations on memory as the primary abstraction--an instruction like "a=b+c;"
needs to behave as though it's reading b and c from memory and storing them
to a, with non-volatile-qualified objects having semantics which are more
rigidly defined than in standard C, but less rigidly defined than volatile-
qualified objects [cached reads need to be invalidated when volatile objects
or targets of non-restrict pointer are written, and cached writes need to
be performed before volatile objects or targets of non-restrict pointers are
are accessed, but reads and writes of declared objects or targets of restrict
pointers may--unlike those of volatile objects--be cached or rearranged at
will.]  Good performance sometimes requires using "restrict", but if one
uses restrict suitably, performance can be better than if one had to use
"volatile" for everything that needed to be sequenced relative to other
"volatile" accesses.
0
supercat
11/29/2015 7:39:26 PM
On Sun, 2015-11-29, Richard Bos wrote:
> Jorgen Grahn <grahn+nntp@snipabacken.se> wrote:
>
>> On Sun, 2015-11-29, Malcolm McLean wrote:
>> > On Sunday, November 29, 2015 at 12:00:34 PM UTC, David Brown wrote:
>> >> On 28/11/15 18:42, Malcolm McLean wrote:
>> >>
>> >> > Your version compiles (on a naive compiler) to
>> >> 
>> >> Why would you want to compare speed or efficiency (of object code) on a
>> >> "naive compiler" ?  You would want to compare it on the best
>> >> optimisation you can get from the compiler.
>> 
>> > If you know your target platform, the of course you profile, or base
>> > the code on how you know the target works.  But if you don't, the
>> > best strategy is to make the optimisation as easy as possible for a
>> > naive compiler. Then you ought to get the optimal result.
>> 
>> But there are no naive compilers today!  And few CPUs that look like
>> e.g. the MC68000 once did, if I understand correctly.
>
> However, there are compilers (and CPUs) that are non-naive in different
> ways,

Yes, but that doesn't change my statement above (and in the part you
snipped).  I'm arguing you don't have to know the CPU, if you allow
the optimizer to sort out the details.

> so unless you know your exact target and also know that this will
> _never_ change, premature optimisation is still unwise.

Not sure I understand your point here. /Premature/ optimization is
premature by definition.  I'm not advocating it.  I'm arguing against
the kinds of optimzations Malcolm suggests, which seem to assume the
code will be better if you imagine a naive compiler and an old CPU.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
11/29/2015 8:14:06 PM
On Sunday, November 29, 2015 at 2:14:21 PM UTC-6, Jorgen Grahn wrote:
> Not sure I understand your point here. /Premature/ optimization is
> premature by definition.  I'm not advocating it.  I'm arguing against
> the kinds of optimzations Malcolm suggests, which seem to assume the
> code will be better if you imagine a naive compiler and an old CPU.

I find the blind faith in optimizers interesting.  For finding out whether
pointers overlap, does it really make more sense to say that people should
write:

    int needle_is_in_haystack(void *needle, void *haystack, int length)
    {
      for (int i=0; i<length; i++)
        if ((char*)needle == ((char*)haystack)+i)
          return 1;
      return 0;
    }

or would it make more sense to have a means of compile-time asserting that
pointers define a universal transitive non-overlapping order [which is true
on most modern machines] and allow code to say:

    int needle_is_in_haystack(void *needle, void *haystack, int length)
    {
      return needle < haystack || needle >= ((char*)haystack)+length);
    }

True, a good compiler might optimize the first to code equivalent to what
a naive compiler could issue for the second, and requiring a compiler to
allow the use of relational operators on unrelated pointers might block
a compiler from being able to use such comparisons as a basis for assuming
that pointers must be related, but as a programmer I'd prefer not to have
to blindly assume that a compiler's going to do something decent with the
first example.

Of course, if there were intrinsics to report whether pointers do or might
overlap [for many applications, a function with 0% false negatives and a
small percentage of false positives may be nearly as useful as one with
0% false positives, but on some platforms such a function may be much
cheaper than a perfect one] those would be even better than having to
use relational operators or hope one's compiler doesn't generate a silly
comparison loop.


0
supercat
11/29/2015 9:05:37 PM
On 28-Nov-15 09:38, David Brown wrote:
> On 28/11/15 08:20, Stephen Sprunk wrote:
>> Aside from Duff's Device (which I also don't completely
>> understand, though it's not as bad as the above), I haven't heard
>> of any serious real-world use of such constructions.
> 
> I have seen a couple of serious uses for such switches, to implement 
> co-routines or light-weight threading in C - especially for very
> small systems.
> 
> <http://dunkels.com/adam/pt/expansion.html>

*scratches head*

I'm not sure I understand what it's doing there, but couldn't it do the
same thing with goto's?

I also wonder how many opportunities for optimization are being missed
because the compiler can't figure out if they're safe with such a weird
structure being used--as apparently happens with Duff's Device.

Trying to outsmart the compiler rarely seems to turn out well.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/30/2015 12:35:28 AM
On Sunday, November 29, 2015 at 4:51:05 PM UTC-6, Stephen Sprunk wrote:
> "Snarky" has a negative connotation that I don't think applies when
> people here give such advice.  Well, at least it doesn't when I do so;
> I'm trying to help people avoid wasted and often counter-productive effort.

The first rule of any kind of optimization effort is to identify what parts
of the code are going to consume enough time to be worth worrying about before
expending any significant effort worrying about them.

My approach, when a bottleneck is found, is to try to figure out how the speed
at which the code is performing a task compares with the maximum possible
speed under best-case circumstances.  If there's not much difference, it may
be worth changing algorithms so as to require less work, but there's no need
to spend effort making the code which does the work more efficient.

While I lack the skill necessary to evaluate the quality of code for modern
CPUs, I often examine the output of the embedded-systems compilers I use in
any situation where something is taking longer than ideal, and I often find
opportunities to improve things.  I don't like using assembly language, but
on simple processors with simple loops it can sometimes pay huge dividends.
More often, though, performance boosts come from figuring out how to write
source that will yield the best output.  For example, if "qbuff_size" and
"qbuff_ptr" are global variables, then on many embedded compilers the code:

    for (int i=0; i<qbuff_size; i++)
      OUTPUT_REGISTER = *qbuff_ptr++;

will reread them both on the assumption that regardless of the type of
OUTPUT_REGISTER, accessing it might have some profound effects on system
state (it's useful to have a category of variables that aren't sequenced
relative to each other, but are sequenced relative to volatile variables;
since C only has volatile-qualified and non-volatile-qualified variables
having default variables be in that category is often less detrimental
to performance than would be having to make a lot more variables volatile).

If I look at the compiled code and see that the compiler is having to
reload those variables within the loop, I can then change it:

    char *p = qbuff_ptr;
    int bytes_left = qbuff_size;
    while(bytes_left--)
      OUTPUT_REGISTER = *p++;

In some other cases, I may see places where the proper fix for code is to add
a restrict qualifier (which can sometimes work wonders for performance).

BTW, one feature that a DSP compiler had which I really miss was a listing
file which would show code after optimizing transforms had been applied
(e.g. with loop induction variables added).  I wonder why I've not seen
such a feature on other compilers since it would seem helpful for trouble-
shooting optimization-related problems.
0
supercat
11/30/2015 2:14:32 AM
gazelle@shell.xmission.com (Kenny McCormack) writes:

> In article <slrnn5m65i.5q5.grahn+nntp@frailea.sa.invalid>,
> Jorgen Grahn  <grahn+nntp@snipabacken.se> wrote:
>
>>Didn't Duff himself note that his Device would soon be defeated by
>>optimizers?  I'm too lazy to check, but I seem to recall that was one
>>of the plot twists, so to speak.
>
> Indeed.  A couple of points that address various issues brought up in this
> thread:
>
>     1) Duff invented this a long time ago, in the 80s if not the 70s, and
> 	in those days, compilers were very naive.  If you wanted efficient
> 	code, you had to write it to be so.  Nowadays, things have changed,
> 	giving rise to the snarky "advice" you see on this forum all the
> 	time about letting the compiler do the optimization, not you.  But
> 	the point is that that this frequently given snarky "advice" was
> 	not appropriate in the days of naive compilers.
>
>     2) Just as a point of trivia, Duff was working for a film studio at the
> 	time.  Might even have been LucasFilm, but I'd have to check that.


Some excerpts from a post to comp.lang.c by Tom Duff himself:

    Somebody claimed that while the device was named for me, I probably
    didn't invent it.  I almost certainly did invent it.  I had
    definitely not seen or heard of it when I came upon it, and nobody
    has ever even claimed prior knowledge, let alone provided dates and
    times.  Note the headers on the message below: apparently I invented
    the device on November 9, 1983, and was proud (or disgusted) enough
    to send mail to dmr.  Please note that I do not claim to have
    invented loop unrolling, merely this particular expression of it in
    C.

    ...

    Somebody invoked (or more properly, banished) the `false god of
    efficiency.'  Careful reading of my original note will put this slur
    to rest.  The alternative to genuflecting before the god of
    code-bumming is finding a better algorithm.  It should be clear that
    none such was available.  If your code is too slow, you must make it
    faster.  If no better algorithm is available, you must trim cycles.

    The same person claimed that the device wouldn't exhibit the desired
    speed-up.  The argument was flawed in two regards: first, it didn't
    address the performance of the device, but rather the performance of
    one of its few uses (implementing memcpy) for which many machines
    have a high-performance idiom.  Second, the poster made his claims
    in the absence of timing data, which renders his assertion suspect.
    A second poster tried the test, but botched the implementation,
    proving only that with diligence it is possible to make anything run
    slowly.

    ...

    I was at Lucasfilm when I invented the device.

    Transformations like this can only be justified by measuring the
    resulting code.  Be careful when you use this thing that you don't
    unwind the loop so much that you overflow your machine's instruction
    cache.  Don't try to be smarter than an over-clever C compiler that
    recognizes loops that implement block move or block clear and
    compiles them into machine idioms.



A copy of the original post can be found at

http://doc.cat-v.org/bell_labs/duffs_device


-- 
Udyant Wig
0
Udyant
11/30/2015 5:35:38 AM
On 30/11/15 01:35, Stephen Sprunk wrote:
> On 28-Nov-15 09:38, David Brown wrote:
>> On 28/11/15 08:20, Stephen Sprunk wrote:
>>> Aside from Duff's Device (which I also don't completely
>>> understand, though it's not as bad as the above), I haven't heard
>>> of any serious real-world use of such constructions.
>>
>> I have seen a couple of serious uses for such switches, to implement 
>> co-routines or light-weight threading in C - especially for very
>> small systems.
>>
>> <http://dunkels.com/adam/pt/expansion.html>
> 
> *scratches head*
> 
> I'm not sure I understand what it's doing there, but couldn't it do the
> same thing with goto's?

(Disclaimer - I haven't used protothreads myself, only read about them.)

Of course you /could/ use goto's, but you would be forced to add a lot
more manual labels.  The point of using the switches here is that you
can reduce everything to reasonably intuitively named macro calls at
reasonably intuitive places in the code - it makes the code look a lot
more like cooperatively multithreaded code.

Roughly speaking, what you get is a state machine, and a structure sort
of like this:

void runThreadX(void) {
	static int state;
	
	switch (state) {
		case 0 :
			doState0();
			state = 1;
			break;
		case 1 :
			doState1();
			state = 2;
			break;
		case 2 :
			if (doState2()) {
				state = 3;	// or whatever
			}
			break;
	}
}

etc.

The macros handle the state machine bit behind the scenes, along with
the scheduling parts.

So it does not do anything that you could not already do using switches
(or gotos, if you want) - it just tries to make it clearer and more
maintainable.


> 
> I also wonder how many opportunities for optimization are being missed
> because the compiler can't figure out if they're safe with such a weird
> structure being used--as apparently happens with Duff's Device.
> 

As I say, I haven't used these myself - but if I am write about the
generated code structures, they should be okay for the compiler's
optimiser.  The macros do "ugly" things like have mismatched brackets
inside a macro, but I don't think they have too much in the way of
mixing switches and other control structures.  (Thinking about that,
this may mean they are not really an example of real-world usage of
mixing switches and other control structures!)

Also, these were developed many years ago, for small microcontrollers
with compilers of little abilities - it is unlikely that the compilers
targeted at the time would have made much better code anyway.

> Trying to outsmart the compiler rarely seems to turn out well.
> 

True indeed.



0
David
11/30/2015 9:20:13 AM
Jorgen Grahn <grahn+nntp@snipabacken.se> writes:
> On Sun, 2015-11-29, Stephen Sprunk wrote:
> ...
>> Interestingly, the Wikipedia article claims that _removing_ Duff's
>> Device turned out to have made XFree86 Server 4.0 both smaller and
>> faster, presumably because it defeated other compiler optimizations.
>> So, I'm not sure there's any remaining argument for such code.
>
> Didn't Duff himself note that his Device would soon be defeated by
> optimizers?  I'm too lazy to check, but I seem to recall that was one
> of the plot twists, so to speak.

I don't believe so.  Tom Duff invented the Device in 1983, and posted
about it to comp.lang.c in 1988.  That article, which includes the
original document from 1983, can be seen here:

http://www.lysator.liu.se/c/duffs-device.html

    The device is legal dpANS C.  I cannot quote chapter and verse,
    but Larry Rosler, who was chairman of the language subcommittee
    (I think), has assured me that X3J11 considered it carefully
    and decided that it was legal. Somewhere I have a note from dmr
    certifying that all the compilers that he believes in accept it.
    Of course, the device is also legal C++, since Bjarne uses it
    in his book.

("dpANS" means "draft proposed American National Standard".)

-- 
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"
0
Keith
11/30/2015 7:01:13 PM
On 11/30/2015 02:01 PM, Keith Thompson wrote:
> Jorgen Grahn <grahn+nntp@snipabacken.se> writes:
>> On Sun, 2015-11-29, Stephen Sprunk wrote:
>> ...
>>> Interestingly, the Wikipedia article claims that _removing_ Duff's
>>> Device turned out to have made XFree86 Server 4.0 both smaller and
>>> faster, presumably because it defeated other compiler optimizations.
>>> So, I'm not sure there's any remaining argument for such code.
>>
>> Didn't Duff himself note that his Device would soon be defeated by
>> optimizers?  I'm too lazy to check, but I seem to recall that was one
>> of the plot twists, so to speak.
> 
> I don't believe so.  Tom Duff invented the Device in 1983, and posted
> about it to comp.lang.c in 1988.  That article, which includes the
> original document from 1983, can be seen here:
> 
> http://www.lysator.liu.se/c/duffs-device.html
> 
>     The device is legal dpANS C.  I cannot quote chapter and verse,
>     but Larry Rosler, who was chairman of the language subcommittee
>     (I think), has assured me that X3J11 considered it carefully
>     and decided that it was legal. Somewhere I have a note from dmr
>     certifying that all the compilers that he believes in accept it.
>     Of course, the device is also legal C++, since Bjarne uses it
>     in his book.
> 
> ("dpANS" means "draft proposed American National Standard".)

That the code was accepted by those compilers does not address the claim
that it was counter-productive, by reason of not being something the
optimizers were built do deal with.
Code with similar control flow can be written using goto's. If the
compiler could optimize the goto version, it seems to me that it should
not be too difficult to make it able to optimize the switch version.

0
James
11/30/2015 7:20:43 PM
On Sunday, November 29, 2015 at 11:36:13 PM UTC-6, Udyant Wig wrote:
>     The same person claimed that the device wouldn't exhibit the desired
>     speed-up.  The argument was flawed in two regards: first, it didn't
>     address the performance of the device, but rather the performance of
>     one of its few uses (implementing memcpy) for which many machines
>     have a high-performance idiom.  Second, the poster made his claims
>     in the absence of timing data, which renders his assertion suspect.
>     A second poster tried the test, but botched the implementation,
>     proving only that with diligence it is possible to make anything run
>     slowly.

Many compilers apply special optimizations to certain recognizable looping
constructs, but cannot apply them to looping constructs they don't
recognize.  On some chips (e.g. TMS 320C5x), a loop like:

    int i,n;
    n=something; // Use an auto variable that can't alias anything
    for (i=0; i<n; i++)
      dest[i] = src1[i] + src2[i];

may be optimized into something like:

    int i,n;
    n=something;
    if (!n) goto end_of_loop;
    HARDWARE_LOOP_COUNTER = n-1;
    int *p1 = dest, *p2 = src1, *p3 = src2;
    SPECIAL_LOOP_INSTRUCTION(address of end_of_loop, minus one);
    *p1++ = *p2++ + *p3++;
  end_of_loop:
    ... code which follows loop

I've actually seen the TMS compiler apply such transforms, and have been
quite impressed by them.

Many compiler are unlikely to apply such transformations to a loop which
contains any labels that are reachable from outside, and while using Duff's
Device to unroll a loop 4x might reduce loop overhead by 75% compared with
an unoptimized loop, there's no way it could do as well as the above code
which reduces per-loop overhead by 100% and has a setup time that is likely
to be below that required for Duff's Device.

0
supercat
11/30/2015 7:59:41 PM
On 30-Nov-15 13:20, James Kuyper wrote:
> On 11/30/2015 02:01 PM, Keith Thompson wrote:
>> Jorgen Grahn <grahn+nntp@snipabacken.se> writes:
>>> On Sun, 2015-11-29, Stephen Sprunk wrote:
>>>> Interestingly, the Wikipedia article claims that _removing_
>>>> Duff's Device turned out to have made XFree86 Server 4.0 both
>>>> smaller and faster, presumably because it defeated other
>>>> compiler optimizations. So, I'm not sure there's any remaining
>>>> argument for such code.
>>> 
>>> Didn't Duff himself note that his Device would soon be defeated
>>> by optimizers?  I'm too lazy to check, but I seem to recall that
>>> was one of the plot twists, so to speak.
>> 
>> I don't believe so.  Tom Duff invented the Device in 1983, and
>> posted about it to comp.lang.c in 1988.  That article, which
>> includes the original document from 1983, can be seen here:
>>
>> http://www.lysator.liu.se/c/duffs-device.html
>>
>>     The device is legal dpANS C.  I cannot quote chapter and verse,
>>     but Larry Rosler, who was chairman of the language subcommittee
>>     (I think), has assured me that X3J11 considered it carefully
>>     and decided that it was legal. Somewhere I have a note from dmr
>>     certifying that all the compilers that he believes in accept it.
>>     Of course, the device is also legal C++, since Bjarne uses it
>>     in his book.
>>
>> ("dpANS" means "draft proposed American National Standard".)
> 
> That the code was accepted by those compilers does not address the
> claim that it was counter-productive, by reason of not being
> something the optimizers were built do deal with. Code with similar
> control flow can be written using goto's. If the compiler could
> optimize the goto version, it seems to me that it should not be too
> difficult to make it able to optimize the switch version.

It _could_, but why bother?  Optimizing naïve code has a far larger
payoff because there's more naïve code out there.  Should they have
dedicated logic to recognize Duff's Device and replace it with a
completely different (and probably more naïve) algorithm that performs
better on modern CPUs due to the effects of pipelining, caches, branch
prediction, branch target prediction, etc.?  That seems wasteful, and it
goes against the general C philosophy of assuming the programmer knows
what he's doing--even when he's pointing a gun at his own foot.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
11/30/2015 8:41:46 PM
On 11/30/2015 03:41 PM, Stephen Sprunk wrote:
> On 30-Nov-15 13:20, James Kuyper wrote:
....
>> something the optimizers were built do deal with. Code with similar
>> control flow can be written using goto's. If the compiler could
>> optimize the goto version, it seems to me that it should not be too
>> difficult to make it able to optimize the switch version.
> 
> It _could_, but why bother?  Optimizing naïve code has a far larger
> payoff because there's more naïve code out there.  Should they have
> dedicated logic to recognize Duff's Device and replace it with a
> completely different (and probably more naïve) algorithm that performs
> better on modern CPUs due to the effects of pipelining, caches, branch
> prediction, branch target prediction, etc.?  That seems wasteful, and it
> goes against the general C philosophy of assuming the programmer knows
> what he's doing--even when he's pointing a gun at his own foot.

I'm not talking about dedicated logic to recognize Duff's Device; I'm
talking about generic logic searching for optimization opportunities in
code that makes explicit use of gotos to achieve similar control flows.
If it's capable of recognizing such opportunities in code using gotos,
it shouldn't be hard to modify it to also recognize such opportunities
in code using Duff's device.

It would be helpful, in discussing this issue, if someone could identify
a specific optimization that could apply in a context where Duff's
device correctly describes what should be done, but where the optimizer
is unlikely to recognize that opportunity if Duff's device is actually
used. In particular, how would Duff's device have to be re-written, to
allow such an optimizer to recognized the optimization opportunity?

0
James
11/30/2015 9:22:51 PM
On Monday, November 30, 2015 at 3:23:01 PM UTC-6, James Kuyper wrote:
> It would be helpful, in discussing this issue, if someone could identify
> a specific optimization that could apply in a context where Duff's
> device correctly describes what should be done, but where the optimizer
> is unlikely to recognize that opportunity if Duff's device is actually
> used. In particular, how would Duff's device have to be re-written, to
> allow such an optimizer to recognized the optimization opportunity?

Optimizations based upon loop induction and hoisting are greatly complicated
if there are any branches which enter the loop.  By far the easiest way to
handle the situation is to simply say that if any branch exists into a loop
from outside it, the compiler will simply treat the loop structure as though
it were written with "gotos".

The only way to achieve a performance boost similar to that attempted by
Duff's Device is to code the body of the loop separately from the "warm-up"
and "clean-up" portions.  Note that what makes Duff's Device interesting is
not that it uses a "switch" to run 0-7 individual steps followed by looping
8 steps per iteration, but rather that it uses the *same code* for the warm-
up as for the loop body.  Code which separates the warm-up logic may achieve
performance similar to Duff's Device, but won't be using Duff's Device.

0
supercat
11/30/2015 9:37:57 PM
James Kuyper <jameskuyper@verizon.net> writes:
> On 11/30/2015 02:01 PM, Keith Thompson wrote:
>> Jorgen Grahn <grahn+nntp@snipabacken.se> writes:
>>> On Sun, 2015-11-29, Stephen Sprunk wrote:
>>> ...
>>>> Interestingly, the Wikipedia article claims that _removing_ Duff's
>>>> Device turned out to have made XFree86 Server 4.0 both smaller and
>>>> faster, presumably because it defeated other compiler optimizations.
>>>> So, I'm not sure there's any remaining argument for such code.
>>>
>>> Didn't Duff himself note that his Device would soon be defeated by
>>> optimizers?  I'm too lazy to check, but I seem to recall that was one
>>> of the plot twists, so to speak.
>> 
>> I don't believe so.  Tom Duff invented the Device in 1983, and posted
>> about it to comp.lang.c in 1988.  That article, which includes the
>> original document from 1983, can be seen here:
>> 
>> http://www.lysator.liu.se/c/duffs-device.html
>> 
>>     The device is legal dpANS C.  I cannot quote chapter and verse,
>>     but Larry Rosler, who was chairman of the language subcommittee
>>     (I think), has assured me that X3J11 considered it carefully
>>     and decided that it was legal. Somewhere I have a note from dmr
>>     certifying that all the compilers that he believes in accept it.
>>     Of course, the device is also legal C++, since Bjarne uses it
>>     in his book.
>> 
>> ("dpANS" means "draft proposed American National Standard".)
>
> That the code was accepted by those compilers does not address the claim
> that it was counter-productive, by reason of not being something the
> optimizers were built do deal with.
> Code with similar control flow can be written using goto's. If the
> compiler could optimize the goto version, it seems to me that it should
> not be too difficult to make it able to optimize the switch version.

Ah, I may have misinterpreted the phrase "defeated by optimizers".
I assumed it meant that optimization might cause a compiler to
generate code whose behavior is inconsistent with the intent (that's
not a concern, since Duff's Device is well defined).  But yes,
an optimizing compiler might produce worse code for Duff's Device
than for a more straightforward version of the code.

I once worked with a (non-C) optimizer that did a relatively poor
job optimizing code with goto statements.  The intermediate form it
worked on reflected higher-level control constructs like loops and
if/else statements.  Goto statements had to be translated into that
form and then optimized.  (I'm almost certainly oversimplifying.)

-- 
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"
0
Keith
11/30/2015 10:42:43 PM
Keith Thompson <kst-u@mib.org> wrote:

(snip)
> Ah, I may have misinterpreted the phrase "defeated by optimizers".
> I assumed it meant that optimization might cause a compiler to
> generate code whose behavior is inconsistent with the intent (that's
> not a concern, since Duff's Device is well defined).  But yes,
> an optimizing compiler might produce worse code for Duff's Device
> than for a more straightforward version of the code.
 
> I once worked with a (non-C) optimizer that did a relatively poor
> job optimizing code with goto statements.  The intermediate form it
> worked on reflected higher-level control constructs like loops and
> if/else statements.  Goto statements had to be translated into that
> form and then optimized.  (I'm almost certainly oversimplifying.)

Fortran optimizing compilers used to be good at code with GOTO,
as that was the only way in Fortran 66.  It might be a lost art.

Some years ago, I translated to C a Fortran program that was a 
translation many years earlier of a PL/I program.  The structure
was still there, but hidden in the GOTOs.

The IBM Fortran H compiler has an option to print out a source
listing indented based on nesting. That is, the nesting that it
figures out from all the IF and GOTO statements, and uses when doing
optimization.  (Only when optimization is on.)

I suppose I am not surprised that not all compilers can do that.

-- glen

0
glen
11/30/2015 11:02:17 PM
On Sun, 2015-11-29, supercat@casperkitty.com wrote:
> On Sunday, November 29, 2015 at 2:14:21 PM UTC-6, Jorgen Grahn wrote:
>> Not sure I understand your point here. /Premature/ optimization is
>> premature by definition.  I'm not advocating it.  I'm arguing against
>> the kinds of optimzations Malcolm suggests, which seem to assume the
>> code will be better if you imagine a naive compiler and an old CPU.
>
> I find the blind faith in optimizers interesting.

It was not my intention to display a "blind faith in optimizers".

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
12/1/2015 8:29:39 PM
On Mon, 2015-11-30, Keith Thompson wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
>> On 11/30/2015 02:01 PM, Keith Thompson wrote:
>>> Jorgen Grahn <grahn+nntp@snipabacken.se> writes:
>>>> On Sun, 2015-11-29, Stephen Sprunk wrote:
>>>> ...
>>>>> Interestingly, the Wikipedia article claims that _removing_ Duff's
>>>>> Device turned out to have made XFree86 Server 4.0 both smaller and
>>>>> faster, presumably because it defeated other compiler optimizations.
>>>>> So, I'm not sure there's any remaining argument for such code.
>>>>
>>>> Didn't Duff himself note that his Device would soon be defeated by
>>>> optimizers?  I'm too lazy to check, but I seem to recall that was one
>>>> of the plot twists, so to speak.
>>> 
>>> I don't believe so.  Tom Duff invented the Device in 1983, and posted
>>> about it to comp.lang.c in 1988.  That article, which includes the
>>> original document from 1983, can be seen here:
>>> 
>>> http://www.lysator.liu.se/c/duffs-device.html
>>> 
>>>     The device is legal dpANS C.  I cannot quote chapter and verse,
>>>     but Larry Rosler, who was chairman of the language subcommittee
>>>     (I think), has assured me that X3J11 considered it carefully
>>>     and decided that it was legal. Somewhere I have a note from dmr
>>>     certifying that all the compilers that he believes in accept it.
>>>     Of course, the device is also legal C++, since Bjarne uses it
>>>     in his book.
>>> 
>>> ("dpANS" means "draft proposed American National Standard".)
>>
>> That the code was accepted by those compilers does not address the claim
>> that it was counter-productive, by reason of not being something the
>> optimizers were built do deal with.
>> Code with similar control flow can be written using goto's. If the
>> compiler could optimize the goto version, it seems to me that it should
>> not be too difficult to make it able to optimize the switch version.
>
> Ah, I may have misinterpreted the phrase "defeated by optimizers".
> I assumed it meant that optimization might cause a compiler to
> generate code whose behavior is inconsistent with the intent (that's
> not a concern, since Duff's Device is well defined).

I was not very clear when I wrote that.  I meant "a more
straightforward implementation becomes at least as efficient due to
better optimizers".  (And I'm still not sure Duff ever expressed
that.)

> But yes, an optimizing compiler might produce worse code for Duff's
> Device than for a more straightforward version of the code.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .
0
Jorgen
12/1/2015 8:34:11 PM
Another victim of this problem is va_list on x86-64:
in 32-bit, va_list is a pointer;
in 64-bit, va_list is an array (of 1 element).

If you pass va_list-arguments between functions,
the result might be different between 32- and 64-bit.
0
UTF
12/3/2015 9:37:03 AM
Lrinczy Zsigmond <zsiga@nospam.for.me> writes:

> Another victim of this problem is va_list on x86-64:
> in 32-bit, va_list is a pointer;
> in 64-bit, va_list is an array (of 1 element).
>
> If you pass va_list-arguments between functions,
> the result might be different between 32- and 64-bit.

Which is a good reason to use (va_list *) rather than plain
(va_list) for function parameters.
0
Tim
12/9/2015 8:16:50 PM
Jorgen Grahn <grahn+nntp@snipabacken.se> wrote:

> On Sun, 2015-11-29, Stephen Sprunk wrote:
> ...
> > Interestingly, the Wikipedia article claims that _removing_ Duff's
> > Device turned out to have made XFree86 Server 4.0 both smaller and
> > faster, presumably because it defeated other compiler optimizations.
> > So, I'm not sure there's any remaining argument for such code.
> 
> Didn't Duff himself note that his Device would soon be defeated by
> optimizers?  I'm too lazy to check, but I seem to recall that was one
> of the plot twists, so to speak.

In any case, it was written for a very specific situation, and that
wasn't memcpy(). So it's quite possible that it was sub-optimally
optimisable for memcpy() purposes even back then.

Richard
0
raltbos
12/10/2015 8:36:50 PM
David Brown <david.brown@hesbynett.no> writes:

> On 28/11/15 23:39, Ben Bacarisse wrote:
>> [giving an example re-writing]
>>
>>      for (int i = 0; i < nb; i++, ch <<= 6)
>>           ch += (unsigned char)*utf8++;
>>
>
> I never like using the comma operator.  [...]

Is there some sort of underlying reasoning that motivates that
reaction?  Or is it just personal bias?
0
Tim
2/18/2016 4:35:03 PM
W dniu czwartek, 18 lutego 2016 17:35:14 UTC+1 u=C5=BCytkownik Tim Rentsch =
napisa=C5=82:
> David Brown <david.brown@hesbynett.no> writes:
>=20
> > On 28/11/15 23:39, Ben Bacarisse wrote:
> >> [giving an example re-writing]
> >>
> >>      for (int i =3D 0; i < nb; i++, ch <<=3D 6)
> >>           ch +=3D (unsigned char)*utf8++;
> >>
> >
> > I never like using the comma operator.  [...]
>=20
> Is there some sort of underlying reasoning that motivates that
> reaction?  Or is it just personal bias?

he is lame , and lamas dont use comma operator
0
fir
2/18/2016 4:48:31 PM
On 18/02/16 17:35, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
>> On 28/11/15 23:39, Ben Bacarisse wrote:
>>> [giving an example re-writing]
>>>
>>>       for (int i = 0; i < nb; i++, ch <<= 6)
>>>            ch += (unsigned char)*utf8++;
>>>
>>
>> I never like using the comma operator.  [...]
>
> Is there some sort of underlying reasoning that motivates that
> reaction?  Or is it just personal bias?
>

I think it makes code (such as the example above) less clear, and it 
makes it harder to be sure that the code is correct.  When looking at a 
loop, it is important to understand the entry state, the iteration, and 
the exit condition in order to be confident that it does what you want. 
  Making any of these parts unnecessarily complicated hinders that 
analysis.  To me, the "ch <<= 6" part should not be part of the loop 
control, but inside the loop body.

I also object to the comma operator in general because it does a strange 
thing - it evaluates an expression, then ignores the result, while being 
part of a bigger expression.  Obviously you often ignore the results of 
an expression as expression statements.  But with the comma operator, I 
see no advantages in write "x = y, z;" instead of "y; x = z;".

And for anyone familiar with languages with a more natural use of comma, 
such as Python, the C comma operator is confusing.  In Python, to swap a 
and b you write "a, b = b, a".  In Python, this means replace the 
objects a and b with b and a respectively.  In C, this means "take a, 
evaluate for side-effects, then throw the result away.  Evaluate b = b 
for side-effects, and throw the result away.  Evaluate a for 
side-effects again, and throw away the result".

"Do not use the comma operator" is a rule that is common in programming 
standards, so I am not alone in my dislike for it.  Equally, of course, 
there are lots of people that /do/ use the comma operator - including 
some who are happy with it in some circumstances, and not in others.

0
David
2/18/2016 9:21:56 PM
On Thursday, 18 February 2016 21:22:04 UTC, David Brown  wrote:
<snip>
> I see no advantages in write "x = y, z;" instead of "y; x = z;".
<snip>

Not even the fact that, in the latter, the wrong value gets assigned to x?

"x = y, z;": assign y to x and then evaluate z.
"y; x = z;": evaluate y and then assign z to x.

Perhaps you are (mis)reading the first form as "x = (y, z);"?
0
guinness
2/19/2016 11:11:06 AM
On 19/02/16 12:11, guinness.tony@gmail.com wrote:
> On Thursday, 18 February 2016 21:22:04 UTC, David Brown  wrote:
> <snip>
>> I see no advantages in write "x = y, z;" instead of "y; x = z;".
> <snip>
> 
> Not even the fact that, in the latter, the wrong value gets assigned to x?
> 
> "x = y, z;": assign y to x and then evaluate z.
> "y; x = z;": evaluate y and then assign z to x.
> 
> Perhaps you are (mis)reading the first form as "x = (y, z);"?
> 

There you see how easy it is to get things wrong with the comma operator!

(Obviously people who use it more often are less likely to make such
silly mistakes - and my example there was perhaps more potentially
confusing than something more realistic like "x = y, a = b".)

0
David
2/19/2016 12:49:33 PM
On 2/19/2016 7:49 AM, David Brown wrote:
> On 19/02/16 12:11, guinness.tony@gmail.com wrote:
>> On Thursday, 18 February 2016 21:22:04 UTC, David Brown  wrote:
>> <snip>
>>> I see no advantages in write "x = y, z;" instead of "y; x = z;".
>> <snip>
>>
>> Not even the fact that, in the latter, the wrong value gets assigned to x?
>>
>> "x = y, z;": assign y to x and then evaluate z.
>> "y; x = z;": evaluate y and then assign z to x.
>>
>> Perhaps you are (mis)reading the first form as "x = (y, z);"?
>>
> 
> There you see how easy it is to get things wrong with the comma operator!
> 
> (Obviously people who use it more often are less likely to make such
> silly mistakes - and my example there was perhaps more potentially
> confusing than something more realistic like "x = y, a = b".)
> 

It's very useful when you need two or more independent expressions where
only one is allowed, i.e.

 for (i=0, j=10; i < j; i++,j--) ...

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
0
Jerry
2/19/2016 3:24:08 PM
On 19/02/16 16:24, Jerry Stuckle wrote:
> On 2/19/2016 7:49 AM, David Brown wrote:
>> On 19/02/16 12:11, guinness.tony@gmail.com wrote:
>>> On Thursday, 18 February 2016 21:22:04 UTC, David Brown  wrote:
>>> <snip>
>>>> I see no advantages in write "x = y, z;" instead of "y; x = z;".
>>> <snip>
>>>
>>> Not even the fact that, in the latter, the wrong value gets assigned to x?
>>>
>>> "x = y, z;": assign y to x and then evaluate z.
>>> "y; x = z;": evaluate y and then assign z to x.
>>>
>>> Perhaps you are (mis)reading the first form as "x = (y, z);"?
>>>
>>
>> There you see how easy it is to get things wrong with the comma operator!
>>
>> (Obviously people who use it more often are less likely to make such
>> silly mistakes - and my example there was perhaps more potentially
>> confusing than something more realistic like "x = y, a = b".)
>>
> 
> It's very useful when you need two or more independent expressions where
> only one is allowed, i.e.
> 
>  for (i=0, j=10; i < j; i++,j--) ...
> 

I know people use it for things like that - but I don't like it.  When
there are two or more independent expressions, I want it to be written
as two or more independent expressions - even if that means more lines
of code:

	i = 0;
	j = 10;
	while (i < j) {
		...
		i++;
		j--;
	}


0
David
2/19/2016 4:00:36 PM
On 2/19/2016 11:00 AM, David Brown wrote:
> On 19/02/16 16:24, Jerry Stuckle wrote:
>> On 2/19/2016 7:49 AM, David Brown wrote:
>>> On 19/02/16 12:11, guinness.tony@gmail.com wrote:
>>>> On Thursday, 18 February 2016 21:22:04 UTC, David Brown  wrote:
>>>> <snip>
>>>>> I see no advantages in write "x = y, z;" instead of "y; x = z;".
>>>> <snip>
>>>>
>>>> Not even the fact that, in the latter, the wrong value gets assigned to x?
>>>>
>>>> "x = y, z;": assign y to x and then evaluate z.
>>>> "y; x = z;": evaluate y and then assign z to x.
>>>>
>>>> Perhaps you are (mis)reading the first form as "x = (y, z);"?
>>>>
>>>
>>> There you see how easy it is to get things wrong with the comma operator!
>>>
>>> (Obviously people who use it more often are less likely to make such
>>> silly mistakes - and my example there was perhaps more potentially
>>> confusing than something more realistic like "x = y, a = b".)
>>>
>>
>> It's very useful when you need two or more independent expressions where
>> only one is allowed, i.e.
>>
>>  for (i=0, j=10; i < j; i++,j--) ...
>>
> 
> I know people use it for things like that - but I don't like it.  When
> there are two or more independent expressions, I want it to be written
> as two or more independent expressions - even if that means more lines
> of code:
> 
> 	i = 0;
> 	j = 10;
> 	while (i < j) {
> 		...
> 		i++;
> 		j--;
> 	}
> 
> 

To each their own.  All of the good programmers I know like it.  But it
doesn't mean everyone has to.

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
0
Jerry
2/19/2016 5:08:28 PM
On 19-Feb-16 09:24, Jerry Stuckle wrote:
> On 2/19/2016 7:49 AM, David Brown wrote:
>> There you see how easy it is to get things wrong with the comma
>> operator!
>> 
>> (Obviously people who use it more often are less likely to make
>> such silly mistakes - and my example there was perhaps more
>> potentially confusing than something more realistic like "x = y, a
>> = b".)
> 
> It's very useful when you need two or more independent expressions
> where only one is allowed, i.e.
> 
> for (i=0, j=10; i < j; i++,j--) ...

That's the only case I've found where the comma operator is the best
solution; when a for loop best conveys your intent, you shouldn't use
another loop type just because you need two counters instead of one.

OTOH, I've used the comma operator when it wasn't the best solution,
merely the most expedient one.  For instance, one project needed every
instance of "close(s);" changed to "close(s);s=-1;".  A simple search
and replace wouldn't have worked for non-block if() statements, so I
used "close(s),s=-1;" instead.  As surrounding code was later modified
(for unrelated reasons), it was adjusted to the locally correct form.

S

-- 
Stephen Sprunk         "God does not play dice."  --Albert Einstein
CCIE #3723         "God is an inveterate gambler, and He throws the
K5SSS        dice at every possible opportunity." --Stephen Hawking
0
Stephen
2/19/2016 5:53:55 PM
W dniu pi=C4=85tek, 19 lutego 2016 18:54:16 UTC+1 u=C5=BCytkownik Stephen S=
prunk napisa=C5=82:
> On 19-Feb-16 09:24, Jerry Stuckle wrote:
> > On 2/19/2016 7:49 AM, David Brown wrote:
> >> There you see how easy it is to get things wrong with the comma
> >> operator!
> >>=20
> >> (Obviously people who use it more often are less likely to make
> >> such silly mistakes - and my example there was perhaps more
> >> potentially confusing than something more realistic like "x =3D y, a
> >> =3D b".)
> >=20
> > It's very useful when you need two or more independent expressions
> > where only one is allowed, i.e.
> >=20
> > for (i=3D0, j=3D10; i < j; i++,j--) ...
>=20
> That's the only case I've found where the comma operator is the best
> solution; when a for loop best conveys your intent, you shouldn't use
> another loop type just because you need two counters instead of one.
>=20
> OTOH, I've used the comma operator when it wasn't the best solution,
> merely the most expedient one.  For instance, one project needed every
> instance of "close(s);" changed to "close(s);s=3D-1;".  A simple search
> and replace wouldn't have worked for non-block if() statements, so I
> used "close(s),s=3D-1;" instead.  As surrounding code was later modified
> (for unrelated reasons), it was adjusted to the locally correct form.
>=20
> S
>=20
for me the problem with comma is like oposite - often it doeas not work (co=
mpile error) where i would like to use it - and
this makes is less usable than it could be

could someone maybe explain why it often=20
doesnt compile?
0
fir
2/19/2016 6:58:50 PM
On Friday, February 19, 2016 at 10:00:49 AM UTC-6, David Brown wrote:
> I know people use it for things like that - but I don't like it.  When
> there are two or more independent expressions, I want it to be written
> as two or more independent expressions - even if that means more lines
> of code:

To my mind, modifying multiple variables in a "for" statement's first and
third clauses suggests that those variables are not modified anywhere else
within the loop, and will thus always have the relationship implied by
those assignments.  It can thus make code more readable and understandable
if it helps highlight the relationship between the variables, and can make
code less understandable if one or both variables are modified elsewhere
and thus do not have the indicated relationship.
0
supercat
2/19/2016 7:06:07 PM
On Friday, February 19, 2016 at 5:08:33 PM UTC, Jerry Stuckle wrote:
> On 2/19/2016 11:00 AM, David Brown wrote:
> 
> >> It's very useful when you need two or more independent expressions where
> >> only one is allowed, i.e.
> >>
> >>  for (i=0, j=10; i < j; i++,j--) ...
> >>
> > 
> > I know people use it for things like that - but I don't like it.  When
> > there are two or more independent expressions, I want it to be written
> > as two or more independent expressions - even if that means more lines
> > of code:
> > 
> > 	i = 0;
> > 	j = 10;
> > 	while (i < j) {
> > 		...
> > 		i++;
> > 		j--;
> > 	}
> > 
> > 
> 
> To each their own.  All of the good programmers I know like it.  But it
> doesn't mean everyone has to.
> 
I agree with David there.

A for loop is great for stepping between 0 and N to index an array.
Only rarely do you need to perform an operation several times
on the same data, but it's unexceptional there was well. 
I also accept it for linked lists.

But if there's fancy logic, you should use a while. If the condition
changes in the loop body, or the index variable is manipulated,
for loops aren't a good choice. People are so used to seeing

for(i=0;i<N;i++)
   pay(employee[i]);

that the eye tends to filter out other uses.

0
Malcolm
2/19/2016 8:15:05 PM
Am 19.02.2016 um 16:24 schrieb Jerry Stuckle:
> 
> It's very useful when you need two or more independent expressions where
> only one is allowed, i.e.
> 
>  for (i=0, j=10; i < j; i++,j--) ...
> 
There are only a handful of cases where a the comma operator is actually
helpful, and one of them are complicated loops that include "continue"
expressions.

For example, consider

do {
	... some complicated stuff...
	if (condition)
		continue;
	... more complicated stuff...
} while(increment1++,pointer1++,++i < count);

This way, one can ensure that the dependent variables "increment1",
"pointer1" and "i" remain consistent throughout the loop. If the comma
operator would not exist, the simple "continue" would not be possible
because the loop condition could not increment additional variables as
part of the side-effect of the comma operator. Or rather, the same loop
would look more convoluted and not less convoluted.

Yes, I agree, such uses are rare.


0
Thomas
2/19/2016 11:44:30 PM
fir <profesor.fir@gmail.com> writes:

[...]
> for me the problem with comma is like oposite - often it doeas not
> work (compile error) where i would like to use it - and this makes is
> less usable than it could be
>
> could someone maybe explain why it often 
> doesnt compile?

Can you give an example of code where you thought a comma
operator would (or should?) work but it didn't for some reason?
0
Tim
2/24/2016 5:40:11 PM
W dniu =C5=9Broda, 24 lutego 2016 18:40:21 UTC+1 u=C5=BCytkownik Tim Rentsc=
h napisa=C5=82:
> fir <profesor.fir@gmail.com> writes:
>=20
> [...]
> > for me the problem with comma is like oposite - often it doeas not
> > work (compile error) where i would like to use it - and this makes is
> > less usable than it could be
> >
> > could someone maybe explain why it often=20
> > doesnt compile?
>=20
> Can you give an example of code where you thought a comma
> operator would (or should?) work but it didn't for some reason?

i think it should work almost always,
esp when you want to avoid {} block
by turning ; into ,
It does not work in some cases (i=20
remember it from memory)

Right now i cannot check it, must=20
go out the house for about 1 hour - maybe you will be able to find it in me=
anwhile (do some experiments) ?

0
fir
2/24/2016 6:24:40 PM
W dniu =C5=9Broda, 24 lutego 2016 19:24:56 UTC+1 u=C5=BCytkownik fir napisa=
=C5=82:
> W dniu =C5=9Broda, 24 lutego 2016 18:40:21 UTC+1 u=C5=BCytkownik Tim Rent=
sch napisa=C5=82:
> > fir <profesor.fir@gmail.com> writes:
> >=20
> > [...]
> > > for me the problem with comma is like oposite - often it doeas not
> > > work (compile error) where i would like to use it - and this makes is
> > > less usable than it could be
> > >
> > > could someone maybe explain why it often=20
> > > doesnt compile?
> >=20
> > Can you give an example of code where you thought a comma
> > operator would (or should?) work but it didn't for some reason?
>=20
> i think it should work almost always,
> esp when you want to avoid {} block
> by turning ; into ,
> It does not work in some cases (i=20
> remember it from memory)
>=20
> Right now i cannot check it, must=20
> go out the house for about 1 hour - maybe you will be able to find it in =
meanwhile (do some experiments) ?

one case i found in quick (must go outside as i said) is

int a=3D0,
int b=3D0,
if(a=3D=3D0) b=3D1;

now it will break and i dislike it - not sure if those are the only case (i=
 mean such
lists of commands where you got ifs of
other such kind of statements )

0
fir
2/24/2016 6:31:35 PM
David Brown <david.brown@hesbynett.no> writes:

> On 18/02/16 17:35, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> On 28/11/15 23:39, Ben Bacarisse wrote:
>>>> [giving an example re-writing]
>>>>
>>>>       for (int i = 0; i < nb; i++, ch <<= 6)
>>>>            ch += (unsigned char)*utf8++;
>>>
>>> I never like using the comma operator.  [...]
>>
>> Is there some sort of underlying reasoning that motivates that
>> reaction?  Or is it just personal bias?
>
> I think it makes code (such as the example above) less clear, and it
> makes it harder to be sure that the code is correct.

This sentence is one of those statements that doesn't really say
anything.  Whether you like something is a subjective statement.
Whether you think something is clear, or hard to understand, is a
subjective statement.  What I'm hoping for is some sort of
objective reasoning, not just (re-)statements of personal opinion.

> When looking at
> a loop, it is important to understand the entry state, the iteration,
> and the exit condition in order to be confident that it does what you
> want.

Sure.

> Making any of these parts unnecessarily complicated hinders that
> analysis.

Same problem as the first sentence - "unnecessarily complicated"
is a subjective measure.

> To me, the "ch <<= 6" part should not be part of the loop
> control, but inside the loop body.

You think that.  The person who wrote it may think of it as being
part of the iteration.  Do you think it is _never_ appropriate
to write loops that have multiple iteration actions?  And more
importantly, if you do, what reasoning explains that reaction?

> I also object to the comma operator in general because it does a
> strange thing - it evaluates an expression, then ignores the result,
> while being part of a bigger expression.  Obviously you often ignore
> the results of an expression as expression statements.

I don't know why you think of it as strange.  Expressions in the
first and third clauses of a 'for()' clause are executed purely
for effect and not for value, but they are expressions, not
statements.  Having multiple actions in those places is not
very much different than having multiple statements in a block.

> But with the
> comma operator, I see no advantages in write "x = y, z;" instead of
> "y; x = z;".

(Corrected to "x = (y, z);".)  There are several.  First the
context may not allow writing a statement, but would allow use
of a comma operator.  Most commonly this situation occurs with
loops or if()'s, but may occur other places (eg, expressions in
an initializer).  Second the context may allow multiple actions
to be written as statements but there is some sort of collateral
benefit (eg, alignment of parallel constructions) to write those
using a comma operator instead.  Third, in some cases a series
of simple expressions could be written as statements, but
instead comma operators are used to indicate a conceptual
grouping that the author considers it useful to express.  The
third case has an analogy in regular English with semicolon.  In
most cases sentences are written as stand-alone units and ended
with a dot;  in some cases though it helps to join two related
sentences with a semicolon.  The use of comma operators is
very much (in certain cases) just like the use of semicolons
in regular prose.  Certainly all C programs can be written
without using any comma operators, just as all monographs can be
written without using any semicolons.  But making use of comma
operators (and semicolons) allows more faithful expression of
the author's intent.  Surely there is some value in that.

> And for anyone familiar with languages with a more natural use of
> comma, such as Python, the C comma operator is confusing.  In
> Python, to swap a and b you write "a, b = b, a".  In Python, this
> means replace the objects a and b with b and a respectively.  In
> C, this means "take a, evaluate for side-effects, then throw the
> result away.  Evaluate b = b for side-effects, and throw the
> result away.  Evaluate a for side-effects again, and throw away
> the result".

I program in Python, and also other languages where comma means
something different than it does in C.  I have no trouble
keeping the different uses straight, nor have I ever seen such
confusion in any other experienced programmer.  In my view
anyone who remains confused on this sort of minor point either
shouldn't be programming in the first place, or just isn't
trying.  Do you have any kind of response to that statement?

> "Do not use the comma operator" is a rule that is common in
> programming standards, so I am not alone in my dislike for it.

I realize that's true, but that's not a reason.  I'm looking for
something more than just a statement of opinion, and there can be
collective opinion just as there is individual opinion.  I don't
remember ever seeing any rationale for not using comma operators
that didn't boil down to just opinion or circular explanations.
This motivates me to ask about it.

> Equally, of course, there are lots of people that /do/ use the
> comma operator - including some who are happy with it in some
> circumstances, and not in others.

Let me say something I should have stressed at the beginning,
which is I'm not trying to challenge your views or get you to
change your mind.  I'm just trying to understand why you think
what you do think.
0
Tim
2/25/2016 12:28:40 AM
Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
>> On 18/02/16 17:35, Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>>
>>>> On 28/11/15 23:39, Ben Bacarisse wrote:
>>>>> [giving an example re-writing]
>>>>>
>>>>>        for (int i = 0; i < nb; i++, ch <<= 6)
>>>>>             ch += (unsigned char)*utf8++;
>>>>
>>>> I never like using the comma operator.  [...]
>>>
>>> Is there some sort of underlying reasoning that motivates that
>>> reaction?  Or is it just personal bias?
>>
>> I think it makes code (such as the example above) less clear, and it
>> makes it harder to be sure that the code is correct.
>
> This sentence is one of those statements that doesn't really say
> anything.  Whether you like something is a subjective statement.
> Whether you think something is clear, or hard to understand, is a
> subjective statement.  What I'm hoping for is some sort of
> objective reasoning, not just (re-)statements of personal opinion.

Surely clarity is in the eye of the beholder and is therefore 
subjective?  If you are looking for an objective definition of code 
clarity, you are on a fools errand.

-- 
Ian Collins
0
Ian
2/25/2016 7:17:51 AM
W dniu czwartek, 25 lutego 2016 01:28:51 UTC+1 u=C5=BCytkownik Tim Rentsch =
napisa=C5=82:
> David Brown <david.brown@hesbynett.no> writes:
>=20
> > On 18/02/16 17:35, Tim Rentsch wrote:
> >> David Brown <david.brown@hesbynett.no> writes:
> >>
> >>> On 28/11/15 23:39, Ben Bacarisse wrote:
> >>>> [giving an example re-writing]
> >>>>
> >>>>       for (int i =3D 0; i < nb; i++, ch <<=3D 6)
> >>>>            ch +=3D (unsigned char)*utf8++;
> >>>
> >>> I never like using the comma operator.  [...]
> >>
> >> Is there some sort of underlying reasoning that motivates that
> >> reaction?  Or is it just personal bias?
> >
> > I think it makes code (such as the example above) less clear, and it
> > makes it harder to be sure that the code is correct.
>=20
> This sentence is one of those statements that doesn't really say
> anything.  Whether you like something is a subjective statement.
> Whether you think something is clear, or hard to understand, is a
> subjective statement.  What I'm hoping for is some sort of
> objective reasoning, not just (re-)statements of personal opinion.
>=20
> > When looking at
> > a loop, it is important to understand the entry state, the iteration,
> > and the exit condition in order to be confident that it does what you
> > want.
>=20
> Sure.
>=20
> > Making any of these parts unnecessarily complicated hinders that
> > analysis.
>=20
> Same problem as the first sentence - "unnecessarily complicated"
> is a subjective measure.
>=20
> > To me, the "ch <<=3D 6" part should not be part of the loop
> > control, but inside the loop body.
>=20
> You think that.  The person who wrote it may think of it as being
> part of the iteration.  Do you think it is _never_ appropriate
> to write loops that have multiple iteration actions?  And more
> importantly, if you do, what reasoning explains that reaction?
>=20
> > I also object to the comma operator in general because it does a
> > strange thing - it evaluates an expression, then ignores the result,
> > while being part of a bigger expression.  Obviously you often ignore
> > the results of an expression as expression statements.
>=20
> I don't know why you think of it as strange.  Expressions in the
> first and third clauses of a 'for()' clause are executed purely
> for effect and not for value, but they are expressions, not
> statements.  Having multiple actions in those places is not
> very much different than having multiple statements in a block.
>=20
> > But with the
> > comma operator, I see no advantages in write "x =3D y, z;" instead of
> > "y; x =3D z;".
>=20
> (Corrected to "x =3D (y, z);".)  There are several.  First the
> context may not allow writing a statement, but would allow use
> of a comma operator.  Most commonly this situation occurs with
> loops or if()'s, but may occur other places (eg, expressions in
> an initializer).  Second the context may allow multiple actions
> to be written as statements but there is some sort of collateral
> benefit (eg, alignment of parallel constructions) to write those
> using a comma operator instead.  Third, in some cases a series
> of simple expressions could be written as statements, but
> instead comma operators are used to indicate a conceptual
> grouping that the author considers it useful to express.  The
> third case has an analogy in regular English with semicolon.  In
> most cases sentences are written as stand-alone units and ended
> with a dot;  in some cases though it helps to join two related
> sentences with a semicolon.  The use of comma operators is
> very much (in certain cases) just like the use of semicolons
> in regular prose.  Certainly all C programs can be written
> without using any comma operators, just as all monographs can be
> written without using any semicolons.  But making use of comma
> operators (and semicolons) allows more faithful expression of
> the author's intent.  Surely there is some value in that.
>=20
> > And for anyone familiar with languages with a more natural use of
> > comma, such as Python, the C comma operator is confusing.  In
> > Python, to swap a and b you write "a, b =3D b, a".  In Python, this
> > means replace the objects a and b with b and a respectively.  In
> > C, this means "take a, evaluate for side-effects, then throw the
> > result away.  Evaluate b =3D b for side-effects, and throw the
> > result away.  Evaluate a for side-effects again, and throw away
> > the result".
>=20
> I program in Python, and also other languages where comma means
> something different than it does in C.  I have no trouble
> keeping the different uses straight, nor have I ever seen such
> confusion in any other experienced programmer.  In my view
> anyone who remains confused on this sort of minor point either
> shouldn't be programming in the first place, or just isn't
> trying.  Do you have any kind of response to that statement?
>=20
> > "Do not use the comma operator" is a rule that is common in
> > programming standards, so I am not alone in my dislike for it.
>=20
> I realize that's true, but that's not a reason.  I'm looking for
> something more than just a statement of opinion, and there can be
> collective opinion just as there is individual opinion.  I don't
> remember ever seeing any rationale for not using comma operators
> that didn't boil down to just opinion or circular explanations.
> This motivates me to ask about it.
>=20
> > Equally, of course, there are lots of people that /do/ use the
> > comma operator - including some who are happy with it in some
> > circumstances, and not in others.
>=20
> Let me say something I should have stressed at the beginning,
> which is I'm not trying to challenge your views or get you to
> change your mind.  I'm just trying to understand why you think
> what you do think.

as to a,b =3D c, a=20
(which i proposed as a c/c2 sugar long time ago, (also wit a,b=3Df(c,a) and=
 many other good things  )
this kind of "," usage is a part of some Virtua language (lets call it V, g=
ood name for that ), here in c we talk on the ","
as it is in c - so it is a bit big gap to mix one wit another

a,b =3D c, a is also to some extent doubtfull
(though dont looking bad), As i said the most 'doubtfull' operators I know =
are just comma and space (wit nospace, and multispace whose dont necessary =
must be treating like space)

C uses it other way, some lamers dont even knew how it works where they try=
 teach in the same this is 'unclear, (this is stupidity i cannot stand) for=
 me as i said "," in c is fine in handy, though im sorry it 'breaks' in som=
e cases where it could be slightly redefined and continue to work in larger=
 cases

in general it could be used to turn {a;b;c;}
into a,b,c; imo - The return value defined as a last one (or the last that =
returns the value) seems roughly ok - this only shows maybe that such block=
s as {a,b} could also return a value , and probably if statements could als=
o return a value=20

int a =3D if(a) 2; else 3;

it wouldnt bring any harm probably and could be used

btw, does

int a =3D2;

return value? Im not sure..








0
fir
2/25/2016 9:12:19 AM
On 25/02/16 01:28, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
> 
>> On 18/02/16 17:35, Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>>
>>>> On 28/11/15 23:39, Ben Bacarisse wrote:
>>>>> [giving an example re-writing]
>>>>>
>>>>>       for (int i = 0; i < nb; i++, ch <<= 6)
>>>>>            ch += (unsigned char)*utf8++;
>>>>
>>>> I never like using the comma operator.  [...]
>>>
>>> Is there some sort of underlying reasoning that motivates that
>>> reaction?  Or is it just personal bias?
>>
>> I think it makes code (such as the example above) less clear, and it
>> makes it harder to be sure that the code is correct.
> 
> This sentence is one of those statements that doesn't really say
> anything.  Whether you like something is a subjective statement.
> Whether you think something is clear, or hard to understand, is a
> subjective statement.  What I'm hoping for is some sort of
> objective reasoning, not just (re-)statements of personal opinion.
> 

It is going to be impossible to get a good, objective basis (at least
with the time and space practical in a Usenet posting) - but maybe it is
possible to get a little better than a purely subjective and very short
statement on clarity.

Sticking for now with somewhat vague and subjective terms, my dislike of
the comma operator is because I think it makes code harder to read,
harder to maintain, easier to misinterpret, and it makes the structure
of the code less obvious.  Further, I think it is particularly confusing
to those less experienced in C - especially because the comma is used in
a variety of other contexts in C.  On the other hand, I don't object to
it for reasons such as efficiency or compiler issues (such as possible
bugs, missing features or misinterpretations of the standards).

Let me also be clear that I said "I never like using the comma
operator".  I think it /can/ be appropriate in some circumstances.

For example, if you write code with a functional-programming style of
expression (using lots of ?: expressions rather than "if" statements,
recursion rather than loops, etc.) then it is natural to use comma
operators as the equivalent to semicolons in imperative style.  I don't
think such a style is very common in C programming - without other
functional programming support (such as list comprehension or lambdas),
it is rarely the neatest way to express yourself.  But of course some
people use that style more often, and comma operators are going to be
part of that.

And perhaps there are loops for which using commas to allow iteration
over two variables really does improve clarity (as I see it) - and
perhaps I would then use the comma operator.  But I don't think I would
/like/ doing so, and would usually prefer to restructure the code
somehow.  (And I fully accept that other people may view the comma
version as clearer than the restructured version.)


For reference, Wikipedia has some examples at
<https://en.wikipedia.org/wiki/Comma_operator>

Now, you might well argue that most of "examples" section are poor
examples of the use of comma operators - but I think it is telling that
at least one of these examples doesn't compile, and even after
correcting it the result is different from that given in the comments.


>> When looking at
>> a loop, it is important to understand the entry state, the iteration,
>> and the exit condition in order to be confident that it does what you
>> want.
> 
> Sure.
> 
>> Making any of these parts unnecessarily complicated hinders that
>> analysis.
> 
> Same problem as the first sentence - "unnecessarily complicated"
> is a subjective measure.

Let me try to be a little more concrete.  In a loop, if you have a
single variable that is initialised at the start of the loop, that has a
simple exit condition, and that makes strictly monotonic progress
towards that exit, then it becomes very simple to see how the loop works
and that it will finish correctly.  Anything beyond that makes the loop
control more complicated - the loop's control is no longer as obvious.
Thus things that are not strictly part of the loop's control should not
(IMHO) be placed in the controlling expressions.

Look at this example (from the Wikipedia page) :

void rev(char *s, size_t len)
{
    char *first;
    for (first = s, s += len - 1; s >= first; --s)
        putchar(*s);
}

The pointer "first" is not changed as part of the loop control.  Putting
its initialisation there does nothing except make it /look/ like it is
part of the loop control until you read more carefully.  I simply cannot
see any benefit to it compared with:

void rev(char *s, size_t len)
{
    char *first = s;
    for (s += len - 1; s >= first; --s)
        putchar(*s);
}

I would re-structure the code as:

void rev(char *s, size_t len)
{
    for (const char *p = s + len - 1; p >= s; p--) {
        putchar(*p);
    }
}

or to be even more "self-documenting" :

void rev(char *s, size_t len)
{
    const char* first = s;
    const char* last = first + len - 1;

    for (const char *p = last; p >= first; p--) {
        putchar(*p);
    }
}

To my reading, it is more obvious how the loop control works here.

> 
>> To me, the "ch <<= 6" part should not be part of the loop
>> control, but inside the loop body.
> 
> You think that.  The person who wrote it may think of it as being
> part of the iteration.  Do you think it is _never_ appropriate
> to write loops that have multiple iteration actions?  And more
> importantly, if you do, what reasoning explains that reaction?

I think it is rare that multiple iteration actions are appropriate - but
I would not go as far as to say "never".  And I think it is rarer that
the multiple independent iteration actions /need/ to be part of the
controlling expression.

The loop

	for (Init; Cond; Ittr) XX;

is the same (baring things like declaration scope) as:

	Init;
	while (Cond) {
		XX;
		Ittr;
	}

Thus

	for (Init1, Init2; Cond1, Cond2; Ittr1, Ittr2) XX;

is

	Init1, Init2;
	while (Cond1, Cond2) {
		XX;
		Ittr1, Ittr2;
	}

or

	Init1;
	Init2;
	Cond1;
	while (Cond2) {
		XX;
		Ittr1;
		Ittr2;
		Cond1;
	}

Obviously the comma operator is never /necessary/ here.  Depending on
the details, this could be turned back into a for loop controlled by
Init1; Cond2; Ittr1 or Init2; Cond2; Ittr2.  But it might be best
(again, in my subjective value of "best") left as a while loop.


C allows code to be written in a very compact way.  Sometimes that's
fine, but I generally prefer a style that does one thing at a time, one
line at a time.  If there are two variables that are iterated in a loop,
I prefer to be able to say "/there/ is the line that does Ittr1, and
/there/ is the line that does Ittr2".  (It is not a hard and fast rule -
I'll write "*p++ = *q++;" where appropriate.)

> 
>> I also object to the comma operator in general because it does a
>> strange thing - it evaluates an expression, then ignores the result,
>> while being part of a bigger expression.  Obviously you often ignore
>> the results of an expression as expression statements.
> 
> I don't know why you think of it as strange.  Expressions in the
> first and third clauses of a 'for()' clause are executed purely
> for effect and not for value, but they are expressions, not
> statements.  Having multiple actions in those places is not
> very much different than having multiple statements in a block.

The whole "for" statement in C is a little strange, in that the first
and third clauses must be expressions, but they are usually expressions
that you would more commonly use as statements in other parts of the
code.  I guess the fundamental point here is that I think it is strange
that assignment (and other assignment operators) are expressions in C,
rather than statements.

> 
>> But with the
>> comma operator, I see no advantages in write "x = y, z;" instead of
>> "y; x = z;".
> 
> (Corrected to "x = (y, z);".)  There are several.  First the
> context may not allow writing a statement, but would allow use
> of a comma operator.  Most commonly this situation occurs with
> loops or if()'s, but may occur other places (eg, expressions in
> an initializer).  

Certainly there are situations where you can use a comma operator to do
multiple things but where statements are not allowed.  The question is
not whether you /can/ use a comma to combine things in an initialiser or
an "if" condition - the question is whether or not it is /advantageous/.
 You can write:

	if (x = getX(), x > 10) ...

but you can also write:

	x = getX();
	if (x > 10) ...

I don't see any good reasons to prefer the former version, and I see the
functionality of the second version as clearer.  But I accept that there
may be circumstances in which the balance is different (and obviously
different programmers have different views on the clarity and balance).
 Can you give a brief example of a case where refactoring to remove the
comma operator leads to clearly worse code (either worse in your
opinion, or worse in your guess of /my/ opinion).

> Second the context may allow multiple actions
> to be written as statements but there is some sort of collateral
> benefit (eg, alignment of parallel constructions) to write those
> using a comma operator instead.  

Again, I have a hard time imagining real cases where a comma operator
version is better than one without.  But if there are such cases, then I
can agree that the benefits of clearer code layout could well outweigh
my objections to the comma operator.

> Third, in some cases a series
> of simple expressions could be written as statements, but
> instead comma operators are used to indicate a conceptual
> grouping that the author considers it useful to express.  

I think such grouping could be better achieved by other means - blank
lines above and below the group, a block, comments, etc.

> The
> third case has an analogy in regular English with semicolon.  In
> most cases sentences are written as stand-alone units and ended
> with a dot;  in some cases though it helps to join two related
> sentences with a semicolon.  The use of comma operators is
> very much (in certain cases) just like the use of semicolons
> in regular prose.  Certainly all C programs can be written
> without using any comma operators, just as all monographs can be
> written without using any semicolons.  But making use of comma
> operators (and semicolons) allows more faithful expression of
> the author's intent.  Surely there is some value in that.

Certainly there is value in making the author's intent clear.  There are
always many factors involved if one were to try to calculate some sort
of "clarity rating" for a piece of code.  I am just trying to explain
why - for me - the comma operator would get a high negative weighting in
such a calculation.  I don't claim that it would always be an overriding
factor.

(Though I do think that if code has a "clarity rating calculation" with
enough high ups and downs to allow other factors to override a comma
operator, then that code is already suspect - hence I say I never like
using the comma operator, even if it is the best overall choice for a
piece of code.  Sometimes in programming we have to write code that we
don't like - it's not all swings and roundabouts in this job.)

> 
>> And for anyone familiar with languages with a more natural use of
>> comma, such as Python, the C comma operator is confusing.  In
>> Python, to swap a and b you write "a, b = b, a".  In Python, this
>> means replace the objects a and b with b and a respectively.  In
>> C, this means "take a, evaluate for side-effects, then throw the
>> result away.  Evaluate b = b for side-effects, and throw the
>> result away.  Evaluate a for side-effects again, and throw away
>> the result".
> 
> I program in Python, and also other languages where comma means
> something different than it does in C.  I have no trouble
> keeping the different uses straight, nor have I ever seen such
> confusion in any other experienced programmer.  In my view
> anyone who remains confused on this sort of minor point either
> shouldn't be programming in the first place, or just isn't
> trying.  Do you have any kind of response to that statement?

The obvious response is that not everyone is as experienced a
programmer.  And regardless of experience, not every programmer is as
good.  And regardless of experience and ability, not every programmer
covers the same fields or has worked with the same range of coding.
There are countless C programmers who have worked for decades, but who
would find any use of the comma operator strange and unfamiliar.  Just
because someone is an "experienced programmer", does not mean they are
so used to all features of C that the meanings are obvious to them.

> 
>> "Do not use the comma operator" is a rule that is common in
>> programming standards, so I am not alone in my dislike for it.
> 
> I realize that's true, but that's not a reason.  I'm looking for
> something more than just a statement of opinion, and there can be
> collective opinion just as there is individual opinion.  I don't
> remember ever seeing any rationale for not using comma operators
> that didn't boil down to just opinion or circular explanations.
> This motivates me to ask about it.

I think that if you take /any/ rules about style or choice of features
to use, and boil them long enough, you will end up with opinion and
circular explanations at the bottom.  But I hope that I have now given
you at least some hints of a rationale for my opinions here.

> 
>> Equally, of course, there are lots of people that /do/ use the
>> comma operator - including some who are happy with it in some
>> circumstances, and not in others.
> 
> Let me say something I should have stressed at the beginning,
> which is I'm not trying to challenge your views or get you to
> change your mind.  I'm just trying to understand why you think
> what you do think.
> 

Yes, I understand that.  And while you are perhaps not challenging my
views, you are pushing /me/ to challenge my views, which is no bad
thing.  So far, my views here have stood up to my introspection - but
that does not always happen.


0
David
2/25/2016 10:16:53 AM
In article <dj7o4vFj7j3U13@mid.individual.net>,
Ian Collins  <ian-news@hotmail.com> wrote:
....
>Surely clarity is in the eye of the beholder and is therefore 
>subjective?  If you are looking for an objective definition of code 
>clarity, you are on a fools errand.

Indeed.  I am always amused when people start pontificating about
"style/clarity/whatever" here, given the "mathematical certainty/if it's
not in the standards documents, it's crap" attitude that is otherwise
prevalent here.

-- 
Here's a simple test for Fox viewers:

1) Sit back, close your eyes, and think (Yes, I know that's hard for you).
2) Think about and imagine all of your ridiculous fantasies about Barack Obama.
3) Now, imagine that he is white.  Cogitate on how absurd your fantasies
seem now.

See?  That wasn't hard, was it?

0
gazelle
2/25/2016 10:41:20 AM
On Thursday, February 25, 2016 at 10:41:31 AM UTC, Kenny McCormack wrote:
> In article <dj7o4vFj7j3U13@mid.individual.net>,
> Ian Collins  <ian-news@hotmail.com> wrote:
> ...
> >Surely clarity is in the eye of the beholder and is therefore 
> >subjective?  If you are looking for an objective definition of code 
> >clarity, you are on a fools errand.
> 
> Indeed.  I am always amused when people start pontificating about
> "style/clarity/whatever" here, given the "mathematical certainty/if it's
> not in the standards documents, it's crap" attitude that is otherwise
> prevalent here.
> 
Yes, you can do empirical tests on what human programmers find easy
or difficult. Some of the results are surprising, in one experiment code with
comments was found to be harder to interpret than code with the comments
stripped out. However we can't relate most of the results to scientific
fundamentals, and they don't necessarily apply beyond the experiment.
Few real programmers are presented with arbitrary code, for example -
mostly the code is part of a large program they've been working on for
many months, or at least within their domain of expertise - statistical
functions, or 3D graphics code, or database query code. 

0
Malcolm
2/25/2016 10:54:28 AM
On 25/02/2016 10:16, David Brown wrote:
> On 25/02/16 01:28, Tim Rentsch wrote:

>> Same problem as the first sentence - "unnecessarily complicated"
>> is a subjective measure.

> Look at this example (from the Wikipedia page) :
>
> void rev(char *s, size_t len)
> {
>      char *first;
>      for (first = s, s += len - 1; s >= first; --s)
>          putchar(*s);
> }
>
> The pointer "first" is not changed as part of the loop control.  Putting
> its initialisation there does nothing except make it /look/ like it is
> part of the loop control until you read more carefully.  I simply cannot
> see any benefit to it compared with:

That's a good example of what's wrong with for-loops and comma 
operators, although they missed a few opportunities here to cram in as 
much stuff as possible, as for-loops appear to encourage this:

  for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);

First, it took few a seconds of scanning for commas and semicolons to to 
see exactly which bit was which, as everything is pushed over to the 
right. Just the possibility of a comma operator means this has to be 
scanned very carefully.

Then I had to look again to see which exactly was the loop control 
variable and what it's initial value was. I think the whole thing is 
more clearly and simply written as a while:

    char* first = s;
    s += len-1;

    while (s>=first)
        putchar(*s--);

(Actually, any while-statement can be expressed as a for-statement 
instead; it's a wonder then that you ever get to see any at all!)

> or to be even more "self-documenting" :
>
> void rev(char *s, size_t len)
> {
>      const char* first = s;
>      const char* last = first + len - 1;
>
>      for (const char *p = last; p >= first; p--) {
>          putchar(*p);
>      }
> }

Yeah, an extra variable - sorry, two extra variables, as you've sneaked 
one in inside the for statement - and three extra consts really help! 
Compare with my version where I eliminate the 'for' statement 
completely. This isn't really a 'for' loop iteration, it's a while loop.

If you were really intent on using a for-loop, then to my mind it can 
only clearly be expressed with a non-C version (using the same 'first' 
as above as otherwise using 's' as the limit is ambiguous):

   for s := s+len-1 downto first do
     putchar(s)
   end

The deliberate constraints of this form means you know exactly what's 
what. (Although I prefer that such for-loops only iterate over integers 
rather than pointers.)

> 	if (x = getX(), x > 10) ...

What I don't like about using 'comma' is that, just by wrapping a 
function call around this example:

  	if (f(x = getX(), x > 10)) ...

it's now no longer a comma operator, but a comma separator! That means 
being extra careful: when you see a comma, you have to scan outwards to 
work out if it is a separator or not. This version, it's back to being 
an operator:

         if ((f(x = getX()), (x > 10))) ...

But in this near identical version, it's again a separator:

         if (f((x = getX()), (x > 10))) ...

So it gives plenty of scope for fun and games.

-- 
Bartc
0
BartC
2/25/2016 11:02:02 AM
On Thursday, February 25, 2016 at 11:02:18 AM UTC, Bart wrote:
> 
> That's a good example of what's wrong with for-loops and comma 
> operators, although they missed a few opportunities here to cram in as 
> much stuff as possible, as for-loops appear to encourage this:
> 
>   for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);
> 
Yes, that is awful programming.
The flexibility of for loops can be abused. It seldom is in real code, but
the language allows it. It's hard to ban it without also banning things like

for(i=0,j=N-1; i < j; i++,j--)

which is arguably legitimate (though I'd recalculate j = N - i -1  in the loop
body).
>
> > 	if (x = getX(), x > 10) ...
> 
> What I don't like about using 'comma' is that, just by wrapping a 
> function call around this example:
> 
>   	if (f(x = getX(), x > 10)) ...
> 
> it's now no longer a comma operator, but a comma separator! 
>
Agreed, the example is extremely confusing. Anyone who doesn't know would
assume that we are testing x for equality with getX(), and x > 10 is some
sort of constraint which will probably cause a runtime error if violated.
0
Malcolm
2/25/2016 11:21:07 AM
On 25/02/2016 11:21, Malcolm McLean wrote:

> The flexibility of for loops can be abused. It seldom is in real code, but
> the language allows it. It's hard to ban it without also banning things like
>
> for(i=0,j=N-1; i < j; i++,j--)
>
> which is arguably legitimate (though I'd recalculate j = N - i -1  in the loop
> body).

Banning that wouldn't bother me.

What exactly /is/ a for-loop? It used to be a way of iterating from A to 
B inclusive, or 0 to N-1. Some people think it should still limit itself 
to that (with a separate 'forall' to iterate over values.)

With C however it's a free-for-all. Anything is possible, meaning you 
always have to double-check for-loops to see which category they fit into.

Your example has a varying upper limit, which is unusual. It's best 
written as a while-loop then:

   i = 0;
   j = N-1;

   while (i<j) {
     ....
     ++i;
     --j;
   }

(You can calculate j from i inside the loop, but you still need the 
initial assignment outside.)

So, no comma operator, and no for-statement needed.

-- 
Bartc
0
BartC
2/25/2016 12:02:08 PM
On 25/02/16 12:02, BartC wrote:
> On 25/02/2016 10:16, David Brown wrote:
>> On 25/02/16 01:28, Tim Rentsch wrote:
> 
>>> Same problem as the first sentence - "unnecessarily complicated"
>>> is a subjective measure.
> 
>> Look at this example (from the Wikipedia page) :
>>
>> void rev(char *s, size_t len)
>> {
>>      char *first;
>>      for (first = s, s += len - 1; s >= first; --s)
>>          putchar(*s);
>> }
>>
>> The pointer "first" is not changed as part of the loop control.  Putting
>> its initialisation there does nothing except make it /look/ like it is
>> part of the loop control until you read more carefully.  I simply cannot
>> see any benefit to it compared with:
> 
> That's a good example of what's wrong with for-loops and comma
> operators, although they missed a few opportunities here to cram in as
> much stuff as possible, as for-loops appear to encourage this:
> 
>  for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);
> 

For loops certainly /allow/ this sort of thing, but I don't think it is
fair to say they /encourage/ it.

> First, it took few a seconds of scanning for commas and semicolons to to
> see exactly which bit was which, as everything is pushed over to the
> right. Just the possibility of a comma operator means this has to be
> scanned very carefully.

Agreed.

> 
> Then I had to look again to see which exactly was the loop control
> variable and what it's initial value was. I think the whole thing is
> more clearly and simply written as a while:
> 
>    char* first = s;
>    s += len-1;
> 
>    while (s>=first)
>        putchar(*s--);

That's an alternative structure, and I would be happy with that (once
the missing brackets and spaces were added, of course :-)

> 
> (Actually, any while-statement can be expressed as a for-statement
> instead; it's a wonder then that you ever get to see any at all!)

The opposite also applies - for and while loops can be converted back
and forth.  That doesn't mean that one is better than the other - and
often either could be used.

> 
>> or to be even more "self-documenting" :
>>
>> void rev(char *s, size_t len)
>> {
>>      const char* first = s;
>>      const char* last = first + len - 1;
>>
>>      for (const char *p = last; p >= first; p--) {
>>          putchar(*p);
>>      }
>> }
> 
> Yeah, an extra variable - sorry, two extra variables, as you've sneaked
> one in inside the for statement - and three extra consts really help!
> Compare with my version where I eliminate the 'for' statement
> completely. This isn't really a 'for' loop iteration, it's a while loop.

Eliminating variables is not a goal.  I took the function's prototype as
fixed - normally I would have written "void rev(const char* first,
size_t len)".  The "first" and "last" variables (which should actually
have been constants - "const char* const first = s;") are there to
provide names for these expressions in the rest of the function.  They
make the for loop control obvious, and cost nothing.

So yes, these extra variables (or constants as they should have been) help.

And the use of "const" makes it clear what can and cannot change, so
they help too.


> 
> If you were really intent on using a for-loop, then to my mind it can
> only clearly be expressed with a non-C version (using the same 'first'
> as above as otherwise using 's' as the limit is ambiguous):
> 
>   for s := s+len-1 downto first do
>     putchar(s)
>   end

Other languages have different and (usually) more restrictive syntaxes
for for-loops than C.  If I were creating a new language, I too would
pick a more restricted syntax.  But just because C /allows/ a big
variety of controlling expressions, does not mean that we have to use
that freedom.

> 
> The deliberate constraints of this form means you know exactly what's
> what. (Although I prefer that such for-loops only iterate over integers
> rather than pointers.)
> 
>>     if (x = getX(), x > 10) ...
> 
> What I don't like about using 'comma' is that, just by wrapping a
> function call around this example:
> 
>      if (f(x = getX(), x > 10)) ...
> 
> it's now no longer a comma operator, but a comma separator! That means
> being extra careful: when you see a comma, you have to scan outwards to
> work out if it is a separator or not. This version, it's back to being
> an operator:
> 
>         if ((f(x = getX()), (x > 10))) ...
> 
> But in this near identical version, it's again a separator:
> 
>         if (f((x = getX()), (x > 10))) ...
> 
> So it gives plenty of scope for fun and games.
> 

Agreed.  Those are good examples of why I don't like the comma operator.


0
David
2/25/2016 12:19:34 PM
fir <profesor.fir@gmail.com> writes:

> W dniu ?roda, 24 lutego 2016 18:40:21 UTC+1 u?ytkownik Tim Rentsch napisa?:
>> fir <profesor.fir@gmail.com> writes:
>>
>> [...]
>>> for me the problem with comma is like oposite - often it doeas not
>>> work (compile error) where i would like to use it - and this makes is
>>> less usable than it could be
>>>
>>> could someone maybe explain why it often 
>>> doesnt compile?
>>
>> Can you give an example of code where you thought a comma
>> operator would (or should?) work but it didn't for some reason?
>
> i think it should work almost always,
> esp when you want to avoid {} block
> by turning ; into ,
> It does not work in some cases (i 
> remember it from memory)
>
> Right now i cannot check it, must go out the house for about 1
> hour - maybe you will be able to find it in meanwhile (do some
> experiments) ?

I see.  What you're asking about is not where you think comma
will work but where you would like it to work.  There are two
reasons, in different cases, why this happens.

The first reason is that allowing a comma operator would
introduce a syntactic ambiguity, or at least some degree of
syntactic confusion.  Examples of this condition are expressions
in initializers and arguments to function calls.  In those cases,
but perhaps not other similar ones, a comma operator may be used
by adding an extra set of parentheses.

The second reason has to do with syntactic regularity.  Comma
operators may be used as part of expressions but not as a
substitute for semicolon in joining statements and declarations.
For example, C does not allow

    if( ..something.. )  x = 7, goto FOO;

because 'goto FOO' is a statement, not an expression.  There are
some other syntactic restrictions C has like this, or at least
somewhat like it, and they can be annoying at times.  I don't
know what to say beyond this except that C is not a perfect
language, and there isn't much to be done about that so it's
probably better to just accept it and move on.  I would like C
syntax to be more accommodating than it is, but how it is makes
it workable enough in nearly all cases, and those that are left
over don't happen often enough for me to worry about.  For what
that's worth.
0
Tim
2/25/2016 2:52:19 PM
On 2/25/16 1:17 AM, Ian Collins wrote:
> Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> On 18/02/16 17:35, Tim Rentsch wrote:
>>> I think it makes code (such as the example above) less clear, and it
>>> makes it harder to be sure that the code is correct.
>>
>> This sentence is one of those statements that doesn't really say
>> anything.  Whether you like something is a subjective statement.
>> Whether you think something is clear, or hard to understand, is a
>> subjective statement.  What I'm hoping for is some sort of
>> objective reasoning, not just (re-)statements of personal opinion.
>
> Surely clarity is in the eye of the beholder and is therefore
> subjective?  If you are looking for an objective definition of code
> clarity, you are on a fools errand.

The nice thing about that approach though, no matter what the response, 
if it disagrees with your own, you can always complain that it's subjective.


-- 
Randy Howard
(replace the obvious text in the obvious way if you wish to contact me 
directly)
0
Randy
2/25/2016 4:26:50 PM
BartC <bc@freeuk.com> writes:

> On 25/02/2016 10:16, David Brown wrote:
>> On 25/02/16 01:28, Tim Rentsch wrote:
>
>>> Same problem as the first sentence - "unnecessarily complicated"
>>> is a subjective measure.
>
>> Look at this example (from the Wikipedia page) :
>>
>> void rev(char *s, size_t len)
>> {
>>      char *first;
>>      for (first = s, s += len - 1; s >= first; --s)
>>          putchar(*s);

Interesting example.  Remarkable how many errors can be crammed into a
few lines!  I don't think it was written by someone who knows C very
well, and that does not make for strong argument against a single
language feature.  This example is, if anything, an argument again C
overall in that it's too widely used by people who are unaware of the
pitfalls.  The comma operater is not at fault here (though it is
pointless).

>> }
<snip>

> That's a good example of what's wrong with for-loops and comma
> operators,

It's a good exampled of what wrong with the author, but, in your mind,
it's C's fault.

> although they missed a few opportunities here to cram in as
> much stuff as possible, as for-loops appear to encourage this:
>
>  for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);

This does not do what you think it does.  Of course, in your mind that's
another reason why C should not permit one to write such a statement.
Other opinions are possible.

> First, it took few a seconds of scanning for commas and semicolons to
> to see exactly which bit was which, as everything is pushed over to
> the right. Just the possibility of a comma operator means this has to
> be scanned very carefully.
>
> Then I had to look again to see which exactly was the loop control
> variable and what it's initial value was. I think the whole thing is
> more clearly and simply written as a while:
>
>    char* first = s;
>    s += len-1;
>
>    while (s>=first)
>        putchar(*s--);

And it's even better if we (a) use a better function name and better
parameter names; (b) change the newly-declared variable rather than the
parameter; (c) handle zero-length strings without UB; (d) avoid
potential UB with the pointer decrement; (e) tell everyone that we don't
change the passed-in string:

  void print_reverse(const char *str_start, size_t len)
  {
      const char *cp = str_start + len;
      while (cp > str_string)
          putchar(*--cp);
  }

There are some simple rules about how to handle unsigned sizes and
backwards loops, but they seem to be not well-known.

(I'm not knocking your re-write.  Maybe you were trying to keep the
semantics, bugs and all.  I just don't like seeing code like this
uncorrected.)

>>      for (first = s, s += len - 1; s >= first; --s)
>>          putchar(*s);

>
> (Actually, any while-statement can be expressed as a for-statement
> instead; it's a wonder then that you ever get to see any at all!)
>
>> or to be even more "self-documenting" :
>>
>> void rev(char *s, size_t len)
>> {
>>      const char* first = s;
>>      const char* last = first + len - 1;
>>
>>      for (const char *p = last; p >= first; p--) {
>>          putchar(*p);
>>      }
>> }

I think there is more that could be done to help the reader -- see
above.  You may be forced to keep the name and the prototype, but the
fact that the parameter is badly named is not enough reason for a new
variable.

You like your style with extra {}s and so on because it makes for
clearer.  Was it clear that that this function is (albeit only
technically) undefined?

> Yeah, an extra variable - sorry, two extra variables, as you've
> sneaked one in inside the for statement - and three extra consts
> really help! Compare with my version where I eliminate the 'for'
> statement completely. This isn't really a 'for' loop iteration, it's a
> while loop.

Yes, there's no need for all that.

<snip>
-- 
Ben.
0
Ben
2/25/2016 8:32:07 PM
On 25/02/2016 20:32, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:
>
>> On 25/02/2016 10:16, David Brown wrote:
>>> On 25/02/16 01:28, Tim Rentsch wrote:
>>
>>>> Same problem as the first sentence - "unnecessarily complicated"
>>>> is a subjective measure.
>>
>>> Look at this example (from the Wikipedia page) :
>>>
>>> void rev(char *s, size_t len)
>>> {
>>>       char *first;
>>>       for (first = s, s += len - 1; s >= first; --s)
>>>           putchar(*s);
>
> Interesting example.  Remarkable how many errors can be crammed into a
> few lines!  I don't think it was written by someone who knows C very
> well, and that does not make for strong argument against a single
> language feature.  This example is, if anything, an argument again C
> overall in that it's too widely used by people who are unaware of the
> pitfalls.  The comma operater is not at fault here (though it is
> pointless).

I wasn't too interested in how well the original worked, only in the 
style. But I've since tried it and it seems to work.

e, as for-loops appear to encourage this:
>>
>>   for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);
>
> This does not do what you think it does.  Of course, in your mind that's
> another reason why C should not permit one to write such a statement.
> Other opinions are possible.

That's true, I didn't compile it. Use of the 'char*' transforms the 
first comma into a separator for the declaration statement.

And you're right, to me it's another example of the comma operator being 
fragile.

(My example can be made to work, in the same style, by introducing a new 
variable t which steps along the string instead of s.)

>>     char* first = s;
>>     s += len-1;
>>
>>     while (s>=first)
>>         putchar(*s--);
>
> And it's even better if we (a) use a better function name and better
> parameter names; (b) change the newly-declared variable rather than the
> parameter; (c) handle zero-length strings without UB; (d) avoid
> potential UB with the pointer decrement;  (e) tell everyone that we don't
> change the passed-in string:
>
>    void print_reverse(const char *str_start, size_t len)
>    {
>        const char *cp = str_start + len;
>        while (cp > str_string)
>            putchar(*--cp);
>    }
>
> There are some simple rules about how to handle unsigned sizes and
> backwards loops, but they seem to be not well-known.

What's the UB, that the original can end up pointing to the location 
just before the string?

That might be an issue when the string is at address 0x000000. And if 
the string is at the start of an allocation block, at any address, then 
there might be a pointer to just before that allocation at some point, 
and possibly to non-existent memory.

But that pointer will never be dereferenced, although I understand there 
are some hypothetical machines where apparently just the existence of 
such a pointer causes mayhem.

But, if you're going to worry about things like that, then I think your 
version can suffer from the same problem, if the string is not 
zero-terminated. (And that would be a good reason for the caller to have 
to supply the length.)

-- 
Bartc
0
BartC
2/25/2016 9:55:52 PM
BartC <bc@freeuk.com> writes:
> On 25/02/2016 20:32, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
[...]
>>>   for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);
>>
>> This does not do what you think it does.  Of course, in your mind that's
>> another reason why C should not permit one to write such a statement.
>> Other opinions are possible.
>
> That's true, I didn't compile it. Use of the 'char*' transforms the 
> first comma into a separator for the declaration statement.

No, it doesn't.  There is no such thing in C as a "declaration
statement".  Declarations and statements are disjoint.  The first clause
of a for loop can be either (a) an optional expression followed by a
semicolon, or (b) a declaration (which includes a trailing semicolon).
In the original:
    for (first = s, s += len - 1; s >= first; --s)
there are three expressions:
    first = s, s += len - 1
    s >= first
    --s

In your version:
    for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);
the first clause is neither a valid declaration nor a valid expression.
It's a syntax error.

> And you're right, to me it's another example of the comma operator being 
> fragile.

A metaphor: The fact that something breaks when you smash it with a
sledgehammer doesn't imply that it's particularly fragile.

You say that C's for-loops "seem to encourage" the version you
suggested.  In fact they do not, since any C compiler will reject it.

[...]

> What's the UB, that the original can end up pointing to the location 
> just before the string?

Yes.

> That might be an issue when the string is at address 0x000000. And if 
> the string is at the start of an allocation block, at any address, then 
> there might be a pointer to just before that allocation at some point, 
> and possibly to non-existent memory.

It's undefined behavior regardless of where the string is located.  It
might happen to work in some cases.  (On many systems, it might happen
to work in all cases -- until you're demonstrating the code to someone
important.)

> But that pointer will never be dereferenced, although I understand there 
> are some hypothetical machines where apparently just the existence of 
> such a pointer causes mayhem.
>
> But, if you're going to worry about things like that, then I think your 
> version can suffer from the same problem, if the string is not 
> zero-terminated. (And that would be a good reason for the caller to have 
> to supply the length.)

If it's not zero-terminated, then by definition it isn't a string.  In
the standard library, functions that expect pointers to string have
undefined behavior if they're called with a pointer that doesn't point
to a string.  Passing a correct pointer is the caller's responsibility.
Unfortunately, checking the validity of parameter is not always
possible.

A function that takes a pointer to a string and has undefined behavior
given a pointer to an empty string is quite another matter.  If the
restriction is not documented, it's a bug.  If the restriction is
documented, it's probably just poor design, but again, it would be the
caller's responsibility to avoid passing a pointer to an empty string.

-- 
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"
0
Keith
2/25/2016 10:44:30 PM
On 25/02/2016 22:44, Keith Thompson wrote:

> In your version:
>      for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);
> the first clause is neither a valid declaration nor a valid expression.
> It's a syntax error.

You're making too much of this. Here's a version that compiles and runs, 
and is all in one for-statement header:

for (char* first = s, *t =s+ len - 1; t >= first; putchar(*t), --t);

>> And you're right, to me it's another example of the comma operator being
>> fragile.

> A metaphor: The fact that something breaks when you smash it with a
> sledgehammer doesn't imply that it's particularly fragile.

Suppose you start with:

  int i,j;

  for (i=0, j+=N; i<N; ++i,--j) {....}

Then decided to bring the declaration inside:

  for (int i=0, j+=N; i<N; ++i,--j) {....}

This however doesn't work. The comma has been transformed from an 
operator to a separator. There are countless examples of ways this can 
break, sometimes silently, but which nevertheless is not quite what you 
wanted.

That's not hitting anything with a sledgehammer. It's more like brushing 
it with a feather.

> You say that C's for-loops "seem to encourage" the version you
> suggested.  In fact they do not, since any C compiler will reject it.

OK, you're still going on about the fact that I didn't test my example!

>> That might be an issue when the string is at address 0x000000. And if
>> the string is at the start of an allocation block, at any address, then
>> there might be a pointer to just before that allocation at some point,
>> and possibly to non-existent memory.
>
> It's undefined behavior regardless of where the string is located.  It
> might happen to work in some cases.

You're getting hung up on the C code. I can see beyond that to the 
low-level operations that are involved. Those aren't tied to a 
particular language.

>> But, if you're going to worry about things like that, then I think your
>> version can suffer from the same problem, if the string is not
>> zero-terminated. (And that would be a good reason for the caller to have
>> to supply the length.)
>
> If it's not zero-terminated, then by definition it isn't a string.

Well we don't know if rev() expects a string or not, it doesn't say.

But if it isn't a zero-terminated string, then pointing one past the end 
seems to me just as bad as pointing just before the start (or is there a 
special exception in C for this?).

-- 
Bartc
0
BartC
2/25/2016 11:41:58 PM
BartC <bc@freeuk.com> writes:

> On 25/02/2016 20:32, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
<snip>
>>>     char* first = s;
>>>     s += len-1;
>>>
>>>     while (s>=first)
>>>         putchar(*s--);
>>
>> And it's even better if we (a) use a better function name and better
>> parameter names; (b) change the newly-declared variable rather than the
>> parameter; (c) handle zero-length strings without UB; (d) avoid
>> potential UB with the pointer decrement;  (e) tell everyone that we don't
>> change the passed-in string:
>>
>>    void print_reverse(const char *str_start, size_t len)
>>    {
>>        const char *cp = str_start + len;
>>        while (cp > str_string)

Typo: str_start.  I hope your complaint is not based on that.  In fact,
I should have called it "start" because the buffer need not contain a
string at all.

>>            putchar(*--cp);
>>    }
>>
>> There are some simple rules about how to handle unsigned sizes and
>> backwards loops, but they seem to be not well-known.
>
> What's the UB, that the original can end up pointing to the location
> just before the string?

Not can, does.  Always.  (Except when the string is zero length in which
all hell breaks lose).

> That might be an issue when the string is at address 0x000000. And if
> the string is at the start of an allocation block, at any address,
> then there might be a pointer to just before that allocation at some
> point, and possibly to non-existent memory.

Some day we might get machines back that can use segment addressing to
protect against overruns, and not so very long ago (and I image code is
still compiled like this) there were machines whose addressing favoured
using segment-based offsets rather than full 32-bit pointers.  The C
standard was written with this in mind.

> But that pointer will never be dereferenced, although I understand
> there are some hypothetical machines where apparently just the
> existence of such a pointer causes mayhem.

Yes, C takes a rather strict view of this.  After all, once you've made
a pointer that's "out of bounds", why wait to report an error on access?
Your code might go wrong without any accesses being done -- comparisons
will be unpredictable and so on, so declaring that this is a situation
that need not be detected (but could be if the implementation wants to
help out) seems like a good option to me.

> But, if you're going to worry about things like that, then I think
> your version can suffer from the same problem, if the string is not
> zero-terminated. (And that would be a good reason for the caller to
> have to supply the length.)

I don't see that.  Can you give an example?  This matters because my
case is based on the fact that the correct code is not hard to write.
In fact I'd say it's simpler than the incorrect code, and there is
therefore no reason to ignore what some people claim is the overly fussy
C standard.  In this case it actually helps by encouraging simpler code.

Anyway, I'd like to see an example of what you mean.

-- 
Ben.
0
Ben
2/25/2016 11:57:17 PM
On 2/25/2016 4:55 PM, BartC wrote:
> 
> And you're right, to me it's another example of the comma operator being
> fragile.
>

There is nothing fragile about the comma operator.  There is code that
is fragile due to the misuse of the comma (or any other) operator.

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
0
Jerry
2/26/2016 12:50:09 AM
On 25/02/2016 23:57, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:

>> What's the UB, that the original can end up pointing to the location
>> just before the string?
>
> Not can, does.  Always.

When s is 0x00000000 then it might end up pointing somewhere beyond the 
end of the string!

   (Except when the string is zero length in which
> all hell breaks lose).

In the original code, if s was the address 1000, then 'first' is set to 
1000, and s is decremented to 999 when the length is zero.

The next thing it does is test s>=first, or 999>=1000, which will fail. 
What's so bad about that?

>> But, if you're going to worry about things like that, then I think
>> your version can suffer from the same problem, if the string is not
>> zero-terminated. (And that would be a good reason for the caller to
>> have to supply the length.)
>
> I don't see that.  Can you give an example?  This matters because my
> case is based on the fact that the correct code is not hard to write.
> In fact I'd say it's simpler than the incorrect code, and there is
> therefore no reason to ignore what some people claim is the overly fussy
> C standard.  In this case it actually helps by encouraging simpler code.
>
> Anyway, I'd like to see an example of what you mean.

With a non-terminated string, your code starts off with cp pointing to 
just beyond the end of the string:

 >    void print_reverse(const char *str_start, size_t len)
 >    {
 >        const char *cp = str_start + len;

If s is 1000, and len is 16, then cp will be 1016. But if the 'string' 
is in an allocation of exactly 16 bytes starting at 1000, the last byte 
in the allocation will be at 1015.

I can't see that this is any different from pointing at 999.

And the last byte of the string could also be at 0xFFFFFFFF, so cp could 
end up being 0x00000000. This is marginally more likely than s being 
0x00000000 (with that address usually reserved for NULL).

-- 
Bartc
0
BartC
2/26/2016 1:29:38 AM
BartC <bc@freeuk.com> writes:
> On 25/02/2016 22:44, Keith Thompson wrote:
>> In your version:
>>      for (char* first = s, s += len - 1; s >= first; putchar(*s), --s);
>> the first clause is neither a valid declaration nor a valid expression.
>> It's a syntax error.
>
> You're making too much of this. Here's a version that compiles and runs, 
> and is all in one for-statement header:
>
> for (char* first = s, *t =s+ len - 1; t >= first; putchar(*t), --t);

Ok.  Now the first clause is a valid declaration.

But just because you *can* put a lot of code into a for-statement
header, that doesn't mean you *should*.  Would you prefer that the C
language imposed some arbitrary maximum complexity on what can go into
the header of a for loop?  How would you define that?  And why?

>>> And you're right, to me it's another example of the comma operator being
>>> fragile.
>
>> A metaphor: The fact that something breaks when you smash it with a
>> sledgehammer doesn't imply that it's particularly fragile.
>
> Suppose you start with:
>
>   int i,j;
>
>   for (i=0, j+=N; i<N; ++i,--j) {....}
>
> Then decided to bring the declaration inside:
>
>   for (int i=0, j+=N; i<N; ++i,--j) {....}
>
> This however doesn't work. The comma has been transformed from an 
> operator to a separator. There are countless examples of ways this can 
> break, sometimes silently, but which nevertheless is not quite what you 
> wanted.

You're right, it doesn't work; again, you've created a syntax error,
which the compiler will immediately diagnose for you.

> That's not hitting anything with a sledgehammer. It's more like brushing 
> it with a feather.

I disgree.

>> You say that C's for-loops "seem to encourage" the version you
>> suggested.  In fact they do not, since any C compiler will reject it.
>
> OK, you're still going on about the fact that I didn't test my example!

Yes.  If your transformation had produced something that still compiles
but doesn't do what you want, that might be a valid argument that for
loops are "fragile".  If you make a change that causes the code not to
compile, all I can tell you is Don't Do That.

>>> That might be an issue when the string is at address 0x000000. And if
>>> the string is at the start of an allocation block, at any address, then
>>> there might be a pointer to just before that allocation at some point,
>>> and possibly to non-existent memory.
>>
>> It's undefined behavior regardless of where the string is located.  It
>> might happen to work in some cases.
>
> You're getting hung up on the C code. I can see beyond that to the 
> low-level operations that are involved. Those aren't tied to a 
> particular language.

We're talking about C code.  At least I am, and you're specifically
expressing your dislike of C for loops.

>>> But, if you're going to worry about things like that, then I think your
>>> version can suffer from the same problem, if the string is not
>>> zero-terminated. (And that would be a good reason for the caller to have
>>> to supply the length.)
>>
>> If it's not zero-terminated, then by definition it isn't a string.
>
> Well we don't know if rev() expects a string or not, it doesn't say.

And that's a problem.

> But if it isn't a zero-terminated string, then pointing one past the end 
> seems to me just as bad as pointing just before the start (or is there a 
> special exception in C for this?).

Ben's improved version was:

  void print_reverse(const char *str_start, size_t len)
  {
      const char *cp = str_start + len;
      while (cp > str_string)
          putchar(*--cp);
  }

If str_start points to an empty string, it's well behaved if len==0.  If
len==1 it will print the null byte, which typically isn't what you'd
want.  But even then, it constructs a pointer that points just past the
null byte, but it never dereferences it, so there's no problem.  (Yes,
there's a special case: you can construct a pointer just past the end of
an array as long as you don't dereference it.  There is no such special
case for a pointer before the beginning of an array.)

The function's documentation should probably state that str_start must
point to the initial element of an array of at least len characters.

-- 
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"
0
Keith
2/26/2016 1:44:52 AM
On 26/02/2016 01:44, Keith Thompson wrote:
> BartC <bc@freeuk.com> writes:

>> But if it isn't a zero-terminated string, then pointing one past the end
>> seems to me just as bad as pointing just before the start (or is there a
>> special exception in C for this?).
>
> Ben's improved version was:
>
>    void print_reverse(const char *str_start, size_t len)
>    {
>        const char *cp = str_start + len;
>        while (cp > str_string)
>            putchar(*--cp);
>    }
>
> If str_start points to an empty string, it's well behaved if len==0.  If
> len==1 it will print the null byte,

If the string is empty, and len is 1, then the caller is passing invalid 
arguments. We can't do much about that.

  which typically isn't what you'd
> want.  But even then, it constructs a pointer that points just past the
> null byte, but it never dereferences it, so there's no problem.  (Yes,
> there's a special case: you can construct a pointer just past the end of
> an array as long as you don't dereference it.  There is no such special
> case for a pointer before the beginning of an array.)

Now we're getting there. So there's special dispensation for Ben's code, 
but not for mine!

I wonder if the hardware knows about this special rule in C, and 
suspends its normal operation. Or does C do something like always add a 
spare byte to the end of any allocation, just so you can point one past 
the end?

-- 
Bartc
0
BartC
2/26/2016 2:03:16 AM
BartC <bc@freeuk.com> writes:

> On 25/02/2016 23:57, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> What's the UB, that the original can end up pointing to the location
>>> just before the string?
>>
>> Not can, does.  Always.
>
> When s is 0x00000000 then it might end up pointing somewhere beyond the 
> end of the string!
>
>    (Except when the string is zero length in which
>> all hell breaks lose).
>
> In the original code, if s was the address 1000, then 'first' is set to 
> 1000, and s is decremented to 999 when the length is zero.
>
> The next thing it does is test s>=first, or 999>=1000, which will fail. 
> What's so bad about that?
>
>>> But, if you're going to worry about things like that, then I think
>>> your version can suffer from the same problem, if the string is not
>>> zero-terminated. (And that would be a good reason for the caller to
>>> have to supply the length.)
>>
>> I don't see that.  Can you give an example?  This matters because my
>> case is based on the fact that the correct code is not hard to write.
>> In fact I'd say it's simpler than the incorrect code, and there is
>> therefore no reason to ignore what some people claim is the overly fussy
>> C standard.  In this case it actually helps by encouraging simpler code.
>>
>> Anyway, I'd like to see an example of what you mean.
>
> With a non-terminated string, your code starts off with cp pointing to 
> just beyond the end of the string:

By "non-terminated string", do you mean a character array that doesn't
contain a null character?

>  >    void print_reverse(const char *str_start, size_t len)
>  >    {
>  >        const char *cp = str_start + len;
>
> If s is 1000, and len is 16, then cp will be 1016. But if the 'string' 
> is in an allocation of exactly 16 bytes starting at 1000, the last byte 
> in the allocation will be at 1015.

I presume that "s" means "str_start".

Ok, let's assume that 1000 is shorthand for the pointer value
(char*)1000, and that adding 16 to that pointer value yields a pointer
that equals (char*)1016.  We're talking about C, not about machine
language, so none of this is guaranteed by the language, but I'm willing
to assume it for the sake of argument.  (If you're not talking about C,
then there's no such thing as a for loop, so there's nothing left to
discuss.)

If we have an array of 16 characters starting at address 1000, then cp
will point to address 1016.

> I can't see that this is any different from pointing at 999.

C permits you to construct a pointer just past the last element of an
array, but not to dereference such a pointer.  It doesn't permit you to
construct a pointer before the beginning of an array.  (I'm using
"permit" as a shorthand for defined behavior.)

That's the difference.

See N1570 6.5.6 paragraph 8.

> And the last byte of the string could also be at 0xFFFFFFFF, so cp could 
> end up being 0x00000000. This is marginally more likely than s being 
> 0x00000000 (with that address usually reserved for NULL).

Adding 1 to the address of the last element of an array is well defined,
and cannot yield a null pointer.  Which means that, if adding 1 to the
address 0xFFFFFFFF yields the address 0x00000000 *and* 0x00000000 is
used as the representation of the null pointer, then the last byte of a
string *cannot* be at 0xFFFFFFFF.

-- 
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"
0
Keith
2/26/2016 2:19:48 AM
BartC <bc@freeuk.com> writes:
> On 26/02/2016 01:44, Keith Thompson wrote:
[...]
>>        But even then, it constructs a pointer that points just past the
>> null byte, but it never dereferences it, so there's no problem.  (Yes,
>> there's a special case: you can construct a pointer just past the end of
>> an array as long as you don't dereference it.  There is no such special
>> case for a pointer before the beginning of an array.)
>
> Now we're getting there. So there's special dispensation for Ben's code, 
> but not for mine!

Yes, but I'm sure it's nothing personal.

> I wonder if the hardware knows about this special rule in C, and 
> suspends its normal operation. Or does C do something like always add a 
> spare byte to the end of any allocation, just so you can point one past 
> the end?

Not at all.  The C compiler just has to ensure that all objects are
allocated in such a way that a pointer just past the end of the object
can be compared to pointers into the object.  Whether there has to be a
spare byte to make this work depends on the architecture, but typically
there doesn't.

For example, let's assume a 32-bit system with a monolithic address
space running from address 0x00000000 to 0xffffffff.  Suppose you have a
16-byte char array starting at 0xfffffff0.

    char arr[16]; /* allocated at 0xfffffff0
    char *begin = arr;    /* 0xfffffff0 */
    char *end = arr + 16; /* 0x00000000 */

The problem is that (end > begin), which is required to be true, is
going to evluate to false.

All the compiler has to do to avoid this is to refrain from allocating
any objects at the very top of the address space -- an area that's very
like to be reserved to the operating system anyway.  The system can make
use of that region of memory; it just can't use for C objects.

(I'm ignoring physical vs. virtual memory.)

-- 
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"
0
Keith
2/26/2016 3:34:42 AM
On Thursday, February 25, 2016 at 9:34:51 PM UTC-6, Keith Thompson wrote:
> All the compiler has to do to avoid this is to refrain from allocating
> any objects at the very top of the address space -- an area that's very
> like to be reserved to the operating system anyway.  The system can make
> use of that region of memory; it just can't use for C objects.

Actually, the implementation can use the last byte as part of a C object
if the object is static and its address is never taken.  Since many programs
have at least one such object, a monolithic-address machine which placed
static objects at the top of memory could avoid having to worry about any
object's "one-past" pointer wrapping to zero.
0
supercat
2/26/2016 6:27:03 AM
David Brown wrote:
> Look at this example (from the Wikipedia page) :
> 
> void rev(char *s, size_t len)
> {
>     char *first;
>     for (first = s, s += len - 1; s >= first; --s)
>         putchar(*s);
> }
> 
> The pointer "first" is not changed as part of the loop control.  Putting
> its initialisation there does nothing except make it /look/ like it is
> part of the loop control until you read more carefully. I simply cannot
> see any benefit to it compared with:
> 
> void rev(char *s, size_t len)
> {
>     char *first = s;
>     for (s += len - 1; s >= first; --s)
>         putchar(*s);
> }
> 
> I would re-structure the code as:
> 
> void rev(char *s, size_t len)
> {
>     for (const char *p = s + len - 1; p >= s; p--) {
>         putchar(*p);
>     }
> }
> 
> or to be even more "self-documenting" :
> 
> void rev(char *s, size_t len)
> {
>     const char* first = s;
>     const char* last = first + len - 1;
> 
>     for (const char *p = last; p >= first; p--) {
>         putchar(*p);
>     }
> }
> 
> To my reading, it is more obvious how the loop control works here.

I started writing a response to this to point out that your rewrites
have undefined behavior. Then I realized the original does too.
Perhaps one of us should fix the Wikipedia page. (Keith, I'm thinking
of you.)

The example is pretty bad, anyway, both for the reason you point
out and because why copy a parameter into another variable and
then modify the parameter? I would always leave the parameter
value alone and modify the copy. I'm sure it would not be too
hard too come up with a better example, and avoid the undefined
behavior too.

(The undefined behavior arises when p equals first and is then
decremented one more time. It is only undefined behavior when the
parameter s points to the first element of an array, but presumably
that is a typical situation.)

Philip
0
Philip
2/26/2016 9:02:45 AM
BartC <bc@freeuk.com> writes:

> On 25/02/2016 23:57, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> What's the UB, that the original can end up pointing to the location
>>> just before the string?
>>
>> Not can, does.  Always.
>
> When s is 0x00000000 then it might end up pointing somewhere beyond
> the end of the string!

Ah, we are quibbling over just how badly wrong the code is!  A loop
condition of

  while (p >= array_start) ... no other way out of the loop here ...

is always wrong.

The point is rather hard to make in exact terms -- the code in question
always does something undefined when the pointer it is passed is the
start of an array, but that can be other things than the one you
identified.  The code is not even always "wrong" in that it's fine when
called lie this: rev("abc" + 1, 2); but that's not really the point
either.

>   (Except when the string is zero length in which
>> all hell breaks lose).
>
> In the original code, if s was the address 1000, then 'first' is set
> to 1000, and s is decremented to 999 when the length is zero.

No (though presumably you mean len not length).  len is unsigned and
size_t is almost certainly not promoted to int so len - 1 is large and
positive.

> The next thing it does is test s>=first, or 999>=1000, which will
> fail. What's so bad about that?

See above.  C has lots of places where you need to take care when
writing expressions if you want your code to be highly portable.  It
also *tends*to work well when you *don't* take care and you are writing
code for just one machine.  That's one of it's strengths.  The problem
comes when non-portable code is presented as an example of how to
something that can be done simply and portably.

Here, there is a subtle difference between s += len - 1; and s = s + len
- 1; When len is unsigned, the first is almost always wrong but the
second is simply playing a bit fast a lose with pointers.

>>> But, if you're going to worry about things like that, then I think
>>> your version can suffer from the same problem, if the string is not
>>> zero-terminated. (And that would be a good reason for the caller to
>>> have to supply the length.)
>>
>> I don't see that.  Can you give an example?  This matters because my
>> case is based on the fact that the correct code is not hard to write.
>> In fact I'd say it's simpler than the incorrect code, and there is
>> therefore no reason to ignore what some people claim is the overly fussy
>> C standard.  In this case it actually helps by encouraging simpler code.
>>
>> Anyway, I'd like to see an example of what you mean.
>
> With a non-terminated string, your code starts off with cp pointing to
> just beyond the end of the string:
>
>>    void print_reverse(const char *str_start, size_t len)
>>    {
>>        const char *cp = str_start + len;
>
> If s is 1000, and len is 16, then cp will be 1016. But if the 'string'
> is in an allocation of exactly 16 bytes starting at 1000, the last
> byte in the allocation will be at 1015.
>
> I can't see that this is any different from pointing at 999.

That's because you have not read the language standard.  It is designed
to make forward-scanning code simple and easy, but there are pitfalls
going the other way.  That's why people who write a lot of C have got
standard ways to scan backwards.  The general idea is to always point
(or index) just after the place you care about because C permits you do
that for the last element and the first.  If you point to the element
you want, you must take special care not to try to move the pointer
before the first.

<snip>
-- 
Ben.
0
Ben
2/26/2016 11:46:37 AM
On 26/02/2016 11:46, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:

> Ah, we are quibbling over just how badly wrong the code is!  A loop
> condition of
>
>    while (p >= array_start) ... no other way out of the loop here ...
>
> is always wrong.

Always? array_start could be a slice of a larger array so there could be 
valid elements before it. Although this function won't know that unless 
there is some documented agreement with the caller.

>> The next thing it does is test s>=first, or 999>=1000, which will
>> fail. What's so bad about that?

> Here, there is a subtle difference between s += len - 1; and s = s + len
> - 1; When len is unsigned, the first is almost always wrong but the
> second is simply playing a bit fast a lose with pointers.

I didn't notice the size_t in the original code. I invariably use 'int' 
for such things.

But it seems to go back to the problems of mixed sign arithmetic which 
have been discussed a few times. One might reasonably expect that:

    p += a-1;      // char* p; unsigned a;

is equivalent to:

    p += 0-1;

when a is zero.

(Incidentally, here's yet another problem with the comma operator. If 
you mistakenly type:

    printf("%p\n"),p;

instead of

    printf("%p\n",p);

there is no compile error. Just rather puzzling output. It seems to be 
rather good at masking syntax errors! (Although some compilers will warn.))

-- 
Bartc
0
BartC
2/26/2016 12:25:01 PM
On 25/02/16 21:32, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:
> 
>> On 25/02/2016 10:16, David Brown wrote:

>>>
>>> void rev(char *s, size_t len)
>>> {
>>>      const char* first = s;
>>>      const char* last = first + len - 1;
>>>
>>>      for (const char *p = last; p >= first; p--) {
>>>          putchar(*p);
>>>      }
>>> }
> 
> I think there is more that could be done to help the reader -- see
> above.  You may be forced to keep the name and the prototype, but the
> fact that the parameter is badly named is not enough reason for a new
> variable.

I fully agree that changing the prototype and function name would be
best, but if you can't change it, then I think introducing the new
variable is the next best thing.  (Sometimes you want to have a
parameter renaming variable for the opposite reason - the prototype
might use a nice long descriptive name, but you want a convenient short
name in the implementation.)

Choosing not to change the prototype, or the exact functionality and
algorithm (including bugs) was a somewhat arbitrary design decision on
my part - the point was merely to remove the comma operator, and perhaps
show a few other changes, rather than to do a proper reverse function.

One could make the alternative, equally arbitrary, decision that the
function's specification requires s to be non-null and len to be at
least 1, thus removing the potential undefined behaviour.

> 
> You like your style with extra {}s and so on because it makes for
> clearer.  Was it clear that that this function is (albeit only
> technically) undefined?

I don't think the function /is/ undefined.  It has undefined behaviour
for certain inputs (null pointer for s, or 0 len), but that is not the
same thing as saying the function is "technically undefined".  (Or is it?)

And while I admit I did not bother with checking this sort of thing, I
think the changes I made make it easier to find such issues.  (At least,
it makes it easier for /me/ to find such issues.)


> 
>> Yeah, an extra variable - sorry, two extra variables, as you've
>> sneaked one in inside the for statement - and three extra consts
>> really help! Compare with my version where I eliminate the 'for'
>> statement completely. This isn't really a 'for' loop iteration, it's a
>> while loop.
> 
> Yes, there's no need for all that.
> 

I agree that a while loop makes more sense in this case - but that
wasn't really the point I was making.


0
David
2/26/2016 4:29:46 PM
On 26/02/16 17:29, David Brown wrote:
> On 25/02/16 21:32, Ben Bacarisse wrote:

>>
>> You like your style with extra {}s and so on because it makes for
>> clearer.  Was it clear that that this function is (albeit only
>> technically) undefined?
>
> I don't think the function /is/ undefined.  It has undefined behaviour
> for certain inputs (null pointer for s, or 0 len), but that is not the
> same thing as saying the function is "technically undefined".  (Or is it?)
>

I should get think more before posting - the pointer gets decremented 
below the start of the string.  This will be undefined behaviour if that 
address is not valid (but okay if the "s" argument points inside an 
object rather than at the start).  However, on most systems and in most 
circumstances, this will not cause any nasal daemons - I guess that's 
what you mean by /technically/ undefined.

> And while I admit I did not bother with checking this sort of thing, I
> think the changes I made make it easier to find such issues.  (At least,
> it makes it easier for /me/ to find such issues.)
>

0
David
2/26/2016 6:33:51 PM
On 26/02/16 10:02, Philip Lantz wrote:

> I started writing a response to this to point out that your rewrites
> have undefined behavior. Then I realized the original does too.

Yes, bug-for-bug compatibility.  I was only trying to show that the code 
with the comma operator could easily be transformed to remove the comma 
operator and give something that (IMHO) is clearer - I wasn't trying to 
correct the code.

> Perhaps one of us should fix the Wikipedia page. (Keith, I'm thinking
> of you.)
>
> The example is pretty bad, anyway, both for the reason you point
> out and because why copy a parameter into another variable and
> then modify the parameter? I would always leave the parameter
> value alone and modify the copy. I'm sure it would not be too
> hard too come up with a better example, and avoid the undefined
> behavior too.

I agree.  Also as an example of a comma operator, it is rather poor as 
there is no good reason for having it there.  I am sure some fan of the 
comma operator could find a better example where it makes sense.

The same applies to the earlier examples on the Wikipedia page - the 
comma operators are there merely to show that they /can/ be used, not to 
show situations where people might /want/ to use them.  And at least one 
of the examples fails to compile (since it tries to use a declaration 
and a comma operator in the first clause of the for loop).


>
> (The undefined behavior arises when p equals first and is then
> decremented one more time. It is only undefined behavior when the
> parameter s points to the first element of an array, but presumably
> that is a typical situation.)
>
> Philip
>

0
David
2/26/2016 6:35:05 PM
On Friday, February 26, 2016 at 4:30:01 PM UTC, David Brown wrote:
> 
> I don't think the function /is/ undefined.  It has undefined behaviour
> for certain inputs (null pointer for s, or 0 len), but that is not the
> same thing as saying the function is "technically undefined".  (Or is it?)
>
Probably most C functions are in fact undefined for inputs of
null, INT_MAX, N = 0 / -1, SIZE_MAX, strings longer than INT_MAX,
NaN, inf, DBL_MIN, x = y + DBL_EPSILON, and so forth.
>
> I agree that a while loop makes more sense in this case - but that
> wasn't really the point I was making.
>
The function is just

void rev(char *s, int (size_t if you must) len)
{
while(len--)
  putchar(s[len]);
}

that's how any experienced C programmer would write it. Someone's
got into a mess thinking that if you're stepping through an array,
you must use a for loop.
0
Malcolm
2/26/2016 7:03:42 PM
On 26/02/2016 18:35, David Brown wrote:

> The same applies to the earlier examples on the Wikipedia page - the
> comma operators are there merely to show that they /can/ be used, not to
> show situations where people might /want/ to use them.  And at least one
> of the examples fails to compile (since it tries to use a declaration
> and a comma operator in the first clause of the for loop).

Your link (https://en.wikipedia.org/wiki/Comma_operator) which I hadn't 
looked at before, is actually all about the comma operator. So obviously 
it's going to show some contrived uses.

It also goes on to say:

"Further, because it is rarely used outside of specific idioms, and 
easily mistaken with other commas or the semicolon, it is potentially 
confusing and error-prone."

And confusing it certainly is. If you write this for example:

  int a=b,c;

then, despite "=" being followed an expression, the comma isn't an 
operator but a separator, as is usually expected. But it's not until now 
that I have about why it's not a comma operator.

Yet remove the int (this requires that a,b,c are also declared in an 
outer scope):

   a=b,c;

then it /is/ a comma operator! With somewhat different results...

The article also explains why it's not possible to write A[i,j] to do 2D 
indexing, because of the comma operator, and it's necessary to write 
A[i][j]. Allowing A[i,j] would have been more useful IMO and got rid of 
all these gotchas in the syntax.

-- 
Bartc
0
BartC
2/26/2016 7:09:52 PM
On 26/02/16 09:02, Philip Lantz wrote:

> Perhaps one of us should fix the Wikipedia page. (Keith, I'm thinking
> of you.)

I tried that once. The C page was littered with errors. I tried fixing a 
few of them, but the changes were reverted back to incorrectness within 
a day. Admittedly that was a few years ago. Wikipedia might have gained 
a few marbles since then, but I'm not holding my breath.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
2/26/2016 7:49:02 PM
On 26/02/16 19:03, Malcolm McLean wrote:

> void rev(char *s, int (size_t if you must) len)

I must, I must.

> {
> while(len--)
>    putchar(s[len]);
> }
>
> that's how any experienced C programmer would write it.

Are you sure they wouldn't at least[1] assert that s is not a null 
pointer, and that len > 0, and that s[len - 1] is '\0'? (Or, if not an 
assert, an error code.) And would they not take a FILE * as well? And 
would they not check the stream's error indicator?

int rev(FILE *fp, char *s, size_t len)
{
   int rc = 1; /* [2] */
   if(fp != NULL && s != NULL && len > 0 && s[len - 1] == '\0')
   {
     rc = 0;
     while(len--)
     {
       putc(s[len], fp);
     }
     if(ferror(fp))
     {
       rc = -1; /* [2] */
     }
   }
   return rc;
}

[1] Of course, a /really/ experienced programmer would have compiled and 
tested this before posting, which I have not done.
[2] Or whatever sensible convention you wish to use.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
2/26/2016 7:56:03 PM
supercat@casperkitty.com writes:
> On Thursday, February 25, 2016 at 9:34:51 PM UTC-6, Keith Thompson wrote:
>> All the compiler has to do to avoid this is to refrain from allocating
>> any objects at the very top of the address space -- an area that's very
>> like to be reserved to the operating system anyway.  The system can make
>> use of that region of memory; it just can't use for C objects.
>
> Actually, the implementation can use the last byte as part of a C object
> if the object is static and its address is never taken.  Since many programs
> have at least one such object, a monolithic-address machine which placed
> static objects at the top of memory could avoid having to worry about any
> object's "one-past" pointer wrapping to zero.

In principle, sure, but I doubt that it would be worth implementing a
special-case optimization like that for the sake of being able to use a
single byte at the very end of the address space.

-- 
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"
0
Keith
2/26/2016 7:59:14 PM
BartC <bc@freeuk.com> writes:
> On 26/02/2016 18:35, David Brown wrote:
>> The same applies to the earlier examples on the Wikipedia page - the
>> comma operators are there merely to show that they /can/ be used, not to
>> show situations where people might /want/ to use them.  And at least one
>> of the examples fails to compile (since it tries to use a declaration
>> and a comma operator in the first clause of the for loop).
>
> Your link (https://en.wikipedia.org/wiki/Comma_operator) which I hadn't 
> looked at before, is actually all about the comma operator. So obviously 
> it's going to show some contrived uses.

Not necessarily.  The comma operator does have legitimate uses, and it
should be possible to show them.  I'll take a look at the article and
consider updating it.

> It also goes on to say:
>
> "Further, because it is rarely used outside of specific idioms, and 
> easily mistaken with other commas or the semicolon, it is potentially 
> confusing and error-prone."

It can be, but as I said it does have legitimate uses.  The article
(which I haven't read yet) shouldn't be entirely negative.

> And confusing it certainly is. If you write this for example:
>
>   int a=b,c;
>
> then, despite "=" being followed an expression, the comma isn't an 
> operator but a separator, as is usually expected. But it's not until now 
> that I have about why it's not a comma operator.

It's often recommended to declare only a single object in each
declaration.  Such a style avoids confusion.  Of course C lets you write
confusing code; that doesn't mean you have to.

> Yet remove the int (this requires that a,b,c are also declared in an 
> outer scope):
>
>    a=b,c;
>
> then it /is/ a comma operator! With somewhat different results...

The comma symbol is used in multiple contexts for different purposes.
To avoid ambiguity, some contexts (such as function arguments and
initializers) require an *assignment-expression* rather than an
*expression*.  (An assignment-expression is just an expression that
doesn't have a comma operator as its top-level operator.)

Using a different symbol for the comma operator would have avoided this
issue, but there weren't a lot of symbols available; C already uses all
the ASCII punctuation symbols other than @ and $.

I don't think it's nearly as much of a problem as you apparently do.

> The article also explains why it's not possible to write A[i,j] to do 2D 
> indexing, because of the comma operator, and it's necessary to write 
> A[i][j]. Allowing A[i,j] would have been more useful IMO and got rid of 
> all these gotchas in the syntax.

That could have been done by making the expression between the [ and ]
an assignment-expression rater than an expression.

But how often would you really want to use a comma operator as an array
index?

When I was first learning C, most of my previous experience was in
Pascal, which uses A[i,j] to index a multidimensional array.  I read
that C uses A[i][j], thought "hmm, that's interesting", and moved on.

And unlike in Pascal, a C 2-dimensional array really is just an array of
arrays, so the A[i][j] syntax is consistent.  There was no real need to
add another syntax for the same thing.

-- 
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"
0
Keith
2/26/2016 8:27:15 PM
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> BartC <bc@freeuk.com> writes:
[...]
>> I can't see that this is any different from pointing at 999.
>
> That's because you have not read the language standard.  It is designed
> to make forward-scanning code simple and easy, but there are pitfalls
> going the other way.  That's why people who write a lot of C have got
> standard ways to scan backwards.  The general idea is to always point
> (or index) just after the place you care about because C permits you do
> that for the last element and the first.  If you point to the element
> you want, you must take special care not to try to move the pointer
> before the first.
>
> <snip>

Part of the rationale for this, I think, is that supporting a pointer
past the end of an array is easier than supporting one before the
beginning of it.  For an array of large elements, a pointer past
the end just needs a single extra byte (assuming memory needs to
be allocated for the pointer to point to).  More precisely, only a
single extra byte needs to be within the range of valid addresses.
To point one element before the beginning of the array, you'd need
an extra `sizeof (element_type)` bytes.

-- 
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"
0
Keith
2/26/2016 8:41:34 PM
David Brown <david.brown@hesbynett.no> writes:

> On 26/02/16 17:29, David Brown wrote:
>> On 25/02/16 21:32, Ben Bacarisse wrote:
>
>>>
>>> You like your style with extra {}s and so on because it makes for
>>> clearer.  Was it clear that that this function is (albeit only
>>> technically) undefined?
>>
>> I don't think the function /is/ undefined.  It has undefined behaviour
>> for certain inputs (null pointer for s, or 0 len), but that is not the
>> same thing as saying the function is "technically undefined".  (Or is it?)
>>
>
> I should get think more before posting - the pointer gets decremented
> below the start of the string.  This will be undefined behaviour if
> that address is not valid (but okay if the "s" argument points inside
> an object rather than at the start).  However, on most systems and in
> most circumstances, this will not cause any nasal daemons - I guess
> that's what you mean by /technically/ undefined.

Yes, that was the intent but I worded it very badly.  The function as
written is not undefined (in fact you can call it in such a way that
there is no UB) it's just that it triggers undefined behaviour for what
it it clearly supposed to do.

Writing while (p >= start) { ... --p ... } is OK in so very few bizarre
cases that I'd put a huge warning over it to say that I really meant
it.  In all normal cases it suggests the loop must establish an
condition illegal condition.

-- 
Ben.
0
Ben
2/26/2016 8:43:31 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> On Friday, February 26, 2016 at 4:30:01 PM UTC, David Brown wrote:
>> I don't think the function /is/ undefined.  It has undefined behaviour
>> for certain inputs (null pointer for s, or 0 len), but that is not the
>> same thing as saying the function is "technically undefined".  (Or is it?)
>>
> Probably most C functions are in fact undefined for inputs of
> null, INT_MAX, N = 0 / -1, SIZE_MAX, strings longer than INT_MAX,
> NaN, inf, DBL_MIN, x = y + DBL_EPSILON, and so forth.

That depends entirely on the particular function.  (Strings longer than
INT_MAX aren't usually a problem, assuming SIZE_MAX > INT_MAX.)

Any functions that have undefined behavior for certain arguments should
clearly document that behavior.

[...]

-- 
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"
0
Keith
2/26/2016 8:59:09 PM
On 26/02/2016 19:56, Richard Heathfield wrote:
> On 26/02/16 19:03, Malcolm McLean wrote:
>
>> void rev(char *s, int (size_t if you must) len)
>
> I must, I must.
>
>> {
>> while(len--)
>>    putchar(s[len]);
>> }
>>
>> that's how any experienced C programmer would write it.
>
> Are you sure they wouldn't at least[1] assert that s is not a null
> pointer,

Not really. If this was a normal string function, then possibly, if you 
want to allow both "" and NULL to mean an empty string, or just NULL to 
mean no string.

But if the length is supplied, then it doesn't care what s might be when 
len is 0.

The caller can of course be passing invalid data, but it's impossible to 
check that in general. Maybe the caller passes -80 instead of 80 (for 
'int len'), and that can be checked. But what if the caller passes 800 
when the string only has 80 characters.

> and that len > 0, and that s[len - 1] is '\0'?

When len is 0, the loop doesn't execute. (len might end up as -1 or some 
large value of size_t, but it doesn't matter).

And, whether or not s is zero-terminated, s[len-1] would point to the 
last character before entering the while-loop.

-- 
Bartc
0
BartC
2/26/2016 9:04:44 PM
BartC <bc@freeuk.com> writes:

> On 26/02/2016 11:46, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
>
>> Ah, we are quibbling over just how badly wrong the code is!  A loop
>> condition of
>>
>>    while (p >= array_start) ... no other way out of the loop here ...
>>
>> is always wrong.
>
> Always? array_start could be a slice of a larger array so there could
> be valid elements before it. Although this function won't know that
> unless there is some documented agreement with the caller.

Yes, I am very happy to accept the charge of lazy naming.  I should have
found some way to imply that array_start points to the start of some
top-level array rather than an array in a struct or a sub-array (and
those cases need careful handling).

We agree, presumably, that the code which sparked this off is wrong for
it's apparent purpose.

>>> The next thing it does is test s>=first, or 999>=1000, which will
>>> fail. What's so bad about that?
>
>> Here, there is a subtle difference between s += len - 1; and s = s + len
>> - 1; When len is unsigned, the first is almost always wrong but the
>> second is simply playing a bit fast a lose with pointers.
>
> I didn't notice the size_t in the original code. I invariably use
> 'int' for such things.
>
> But it seems to go back to the problems of mixed sign arithmetic which
> have been discussed a few times. One might reasonably expect that:
>
>    p += a-1;      // char* p; unsigned a;
>
> is equivalent to:
>
>    p += 0-1;
>
> when a is zero.

That's just down to the what you consider reasonable.  Others might
consider p += 0u-1; to be a more reasonable substitution.  It seems
unreasonable to me that you'd change the type and hope that the
expression means what you want.

<snip>
-- 
Ben.
0
Ben
2/26/2016 9:11:37 PM
BartC <bc@freeuk.com> writes:
> On 26/02/2016 19:56, Richard Heathfield wrote:
>> On 26/02/16 19:03, Malcolm McLean wrote:
>>
>>> void rev(char *s, int (size_t if you must) len)
>>
>> I must, I must.
>>
>>> {
>>> while(len--)
>>>    putchar(s[len]);
>>> }
>>>
>>> that's how any experienced C programmer would write it.
>>
>> Are you sure they wouldn't at least[1] assert that s is not a null
>> pointer,
>
> Not really. If this was a normal string function, then possibly, if you 
> want to allow both "" and NULL to mean an empty string, or just NULL to 
> mean no string.

IMHO treating a null pointer as if it were a pointer to an empty string
is a bad idea.

[...]

-- 
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"
0
Keith
2/26/2016 9:13:48 PM
On 26/02/16 21:04, BartC wrote:
> On 26/02/2016 19:56, Richard Heathfield wrote:
>> On 26/02/16 19:03, Malcolm McLean wrote:
>>
>>> void rev(char *s, int (size_t if you must) len)
>>
>> I must, I must.
>>
>>> {
>>> while(len--)
>>>    putchar(s[len]);
>>> }
>>>
>>> that's how any experienced C programmer would write it.
>>
>> Are you sure they wouldn't at least[1] assert that s is not a null
>> pointer,
>
> Not really. If this was a normal string function, then possibly, if you
> want to allow both "" and NULL to mean an empty string, or just NULL to
> mean no string.

That's a design issue. Frankly, I'd prefer NULL to mean "the call to 
this function is screwed, so I'd better tell somebody about it", either 
via an assertion or via an error return, depending on the circumstances.

>
> But if the length is supplied, then it doesn't care what s might be when
> len is 0.

Nevertheless, if a 0-length string is being passed, that can be a sign 
that something is wrong. It's not a bad idea to tell somebody about it. 
If they don't listen, that's their problem (and might not be a problem). 
But it's better to moan than to shut up and hope.

>
> The caller can of course be passing invalid data, but it's impossible to
> check that in general. Maybe the caller passes -80 instead of 80 (for
> 'int len'), and that can be checked. But what if the caller passes 800
> when the string only has 80 characters.

The fact that you can't check for everything doesn't mean that you 
shouldn't check for anything.

>
>> and that len > 0, and that s[len - 1] is '\0'?
>
> When len is 0, the loop doesn't execute. (len might end up as -1 or some
> large value of size_t, but it doesn't matter).

The change in len doesn't matter. The 0-length string /might/ matter. It 
depends on the purpose of the function (by which I mean the higher-level 
intent of the code, not the mechanics of printing out a string backwards).

>
> And, whether or not s is zero-terminated, s[len-1] would point to the
> last character before entering the while-loop.

When I went back to the original Wikipedia page to check the function as 
written there, I was surprised to see that the format of the input is 
not stated. The idea of a /non/-null-terminated array of char is by no 
means unheard of in C, but it's sufficiently unusual that it ought to be 
noted in a comment.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
2/26/2016 9:16:41 PM
On Friday, February 26, 2016 at 9:13:55 PM UTC, Keith Thompson wrote:
> 
> IMHO treating a null pointer as if it were a pointer to an empty string
> is a bad idea.
> 
But we're passing len.

I'd expect 
rev(NULL, 0);

to be a no-op.
0
Malcolm
2/27/2016 3:33:29 AM
BartC wrote:
> David Brown wrote:
> > The same applies to the earlier examples on the Wikipedia page - the
> > comma operators are there merely to show that they /can/ be used, not to
> > show situations where people might /want/ to use them.  And at least one
> > of the examples fails to compile (since it tries to use a declaration
> > and a comma operator in the first clause of the for loop).
> 
> Your link (https://en.wikipedia.org/wiki/Comma_operator) which I hadn't 
> looked at before, is actually all about the comma operator. So obviously 
> it's going to show some contrived uses.

Not at all. There certainly exist non-contrived uses of the comma operator
(your opinion notwithstanding), and that article should show them.
0
Philip
2/27/2016 3:53:13 AM
Richard Heathfield wrote:
> 
> On 26/02/16 09:02, Philip Lantz wrote:
> 
> > Perhaps one of us should fix the Wikipedia page. (Keith, I'm thinking
> > of you.)
> 
> I tried that once. The C page was littered with errors. I tried fixing a 
> few of them, but the changes were reverted back to incorrectness within 
> a day. Admittedly that was a few years ago. Wikipedia might have gained 
> a few marbles since then, but I'm not holding my breath.

No, probably not. The last time this happened to me, I was advised that
I should write a short explanation of my change on the talk page, which
presumably an editor would read before reverting the changes. I haven't
bothered to try since.
0
Philip
2/27/2016 3:56:24 AM
Philip Lantz wrote:
> Richard Heathfield wrote:
> > Philip Lantz wrote:
> > > Perhaps one of us should fix the Wikipedia page. (Keith, I'm thinking
> > > of you.)
> > 
> > I tried that once. The C page was littered with errors. I tried fixing a 
> > few of them, but the changes were reverted back to incorrectness within 
> > a day. Admittedly that was a few years ago. Wikipedia might have gained 
> > a few marbles since then, but I'm not holding my breath.
> 
> No, probably not.

In case that wasn't clear, I meant, "No, they probably haven't gained any
marbles."

> The last time this happened to me, I was advised that
> I should write a short explanation of my change on the talk page, which
> presumably an editor would read before reverting the changes. I haven't
> bothered to try since.
0
Philip
2/27/2016 3:58:42 AM
On Friday, February 26, 2016 at 1:10:10 PM UTC-6, Bart wrote:
> And confusing it certainly is. If you write this for example:
> 
>   int a=b,c;
> 
> then, despite "=" being followed an expression, the comma isn't an 
> operator but a separator, as is usually expected. But it's not until now 
> that I have about why it's not a comma operator.
> 
> Yet remove the int (this requires that a,b,c are also declared in an 
> outer scope):
> 
>    a=b,c;
> 
> then it /is/ a comma operator! With somewhat different results...

The comma operator is hardly unique in that regard.  C's declaration and
initialization syntax cause trouble in other ways as well.  For example,
what are the meanings of:

    int *p = 0;
    *p = 0;

The fact that C's declaration syntax was used in a language that formed the
basis for many successful dialects is a good reason to use it, but otherwise
it's not easy for machines to parse, nor for humans to parse, and it's prone
to many misunderstandings.  It's too bad there's no punctuation to separate
the type from the created name, since that would have cleared up lots of
problems.
0
supercat
2/27/2016 4:26:44 PM
On 27/02/2016 16:26, supercat@casperkitty.com wrote:
> On Friday, February 26, 2016 at 1:10:10 PM UTC-6, Bart wrote:
>> And confusing it certainly is. If you write this for example:

> The comma operator is hardly unique in that regard.  C's declaration and
> initialization syntax cause trouble in other ways as well.  For example,
> what are the meanings of:
>
>      int *p = 0;
>      *p = 0;
>
> The fact that C's declaration syntax was used in a language that formed the
> basis for many successful dialects is a good reason to use it, but otherwise
> it's not easy for machines to parse, nor for humans to parse, and it's prone
> to many misunderstandings.  It's too bad there's no punctuation to separate
> the type from the created name, since that would have cleared up lots of
> problems.

The difference with comma is that you don't really need it. Declarations 
are always needed however. And yes you can have some fun with it:

  a(b);

If this a function call; or declaring variable b with type a?

  a*b;

Is this multiplying a with b, and discarding the result; or declaring a 
variable b of type pointer-to-a?

Sometimes it's so bad it's good!

-- 
Bartc
0
BartC
2/27/2016 4:56:21 PM
BartC <bc@freeuk.com> writes:
[...]
> And confusing it certainly is. If you write this for example:
>
>  int a=b,c;
>
> then, despite "=" being followed an expression, the comma isn't an
> operator but a separator, as is usually expected. But it's not until
> now that I have about why it's not a comma operator.
>
> Yet remove the int (this requires that a,b,c are also declared in an
> outer scope):
>
>   a=b,c;
>
> then it /is/ a comma operator! With somewhat different results...
[...]

A more general comment about this.

C's syntax is unusually "dense".  I don't think that's a commonly
used term for it, but what I mean is that it's easy to take a
syntactically valid C program, make a very small change to it, and
end up with something that's still syntactically valid but with a
very different meaning.  The reuse of symbols for different meanings
(",", "*","()") is part of this.  The heavy use of symbols rather
than keywords is another, as is the "=" vs. "==" distinction.

The language is optimized more for writing correct code in the
first place than for detecting incorrect code.

All languages have this problem to some extent.  In any language
that uses "+" for addition and "-" for subtraction, a compiler
can't detect a typo that substitutes "+" for "-".  But the problem
is more apparent in C.

(I suggest that designers of future non-C languages should pay
attention to this issue.)

-- 
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"
0
Keith
2/27/2016 6:27:03 PM
Ian Collins <ian-news@hotmail.com> writes:

> Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> On 18/02/16 17:35, Tim Rentsch wrote:
>>>> David Brown <david.brown@hesbynett.no> writes:
>>>>
>>>>> On 28/11/15 23:39, Ben Bacarisse wrote:
>>>>>> [giving an example re-writing]
>>>>>>
>>>>>>        for (int i = 0; i < nb; i++, ch <<= 6)
>>>>>>             ch += (unsigned char)*utf8++;
>>>>>
>>>>> I never like using the comma operator.  [...]
>>>>
>>>> Is there some sort of underlying reasoning that motivates that
>>>> reaction?  Or is it just personal bias?
>>>
>>> I think it makes code (such as the example above) less clear, and it
>>> makes it harder to be sure that the code is correct.
>>
>> This sentence is one of those statements that doesn't really say
>> anything.  Whether you like something is a subjective statement.
>> Whether you think something is clear, or hard to understand, is a
>> subjective statement.  What I'm hoping for is some sort of
>> objective reasoning, not just (re-)statements of personal opinion.
>
> Surely clarity is in the eye of the beholder and is therefore
> subjective?  If you are looking for an objective definition of code
> clarity, you are on a fools errand.

What I am looking for is David Brown's reasons, either objective
or subjective, that he never likes using the comma operator.  My
hope is that at least some of those reasons will be objective,
because then I expect to learn something.  Conversely, if all of
them are purely subjective, I don't learn anything.  Saying he
doesn't like it, he thinks it makes code less clear, he thinks it
makes it harder to read, he thinks it makes code less obvious
(which he did not say, but just as an example), etc, all amount
to the same thing from my point of view - they might tell me
something about David Brown, but they don't tell me anything
about anyone else or inherent in the comma operator itself.

Incidentally, I believe the issue raised in your first sentence
is a larger and more complicated topic than the question itself
suggests, but since it doesn't really bear on my response I will
leave that discussion for another day.
0
Tim
3/1/2016 5:26:54 PM
Randy Howard <rhoward.mx@EverybodyUsesIt.com> writes:

> On 2/25/16 1:17 AM, Ian Collins wrote:
>> Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>>
>>>> On 18/02/16 17:35, Tim Rentsch wrote:
>>>> I think it makes code (such as the example above) less clear, and it
>>>> makes it harder to be sure that the code is correct.
>>>
>>> This sentence is one of those statements that doesn't really say
>>> anything.  Whether you like something is a subjective statement.
>>> Whether you think something is clear, or hard to understand, is a
>>> subjective statement.  What I'm hoping for is some sort of
>>> objective reasoning, not just (re-)statements of personal opinion.
>>
>> Surely clarity is in the eye of the beholder and is therefore
>> subjective?  If you are looking for an objective definition of code
>> clarity, you are on a fools errand.
>
> The nice thing about that approach though, no matter what the
> response, if it disagrees with your own, you can always complain that
> it's subjective.

To my way of thinking this statement is nonsensical.  If what is
being offered is merely a personal view, there is no sense in
agreeing or disagreeing with it;  the speaker is the ultimate
authority on his or her own opinions, and for all practical
purposes any statement of opinion can be treated as a fact.  As
for whether a particular statement is an objective statement or a
subjective one, that is an objective question - a statement is
objective if it can be confirmed (or disproven) by an independent
outside observer.  If all parties agree that such an observer can
accurately determine the truth value of a given proposition then
the proposition is an objective statement, and otherwise it isn't.
0
Tim
3/1/2016 5:44:13 PM
On Tuesday, March 1, 2016 at 5:27:06 PM UTC, Tim Rentsch wrote:
>
> What I am looking for is David Brown's reasons, either objective
> or subjective, that he never likes using the comma operator.  My
> hope is that at least some of those reasons will be objective,
> because then I expect to learn something.
>
It's hard to make objective claims about human psychology.
I claimed that humans cannot deal with more than three levels of
indirection, nesting, parentheses and so on, on the basis that we
live in a three dimensional world. You can't have a more objective,
irrefutable observation than that. But some people simply said that,
no problem, they can visualise the relationships. So there's no
real answer to that, other than setting up experiments, which are
notoriously difficult to get right.

Clearly, comma operators can be used to create correct programming
constructs. Clearly, C is Turing complete without them. That's the end
of the objective observations. Everything else is "I find the syntax difficult,
the programs hard to follow". To my mind that's pretty obviously the case,
except in a few limited places in for loops, the comma operator is
a readability nightmare. But if someone simply asserts the opposite,
you have to set up the experiments to refute him.


0
Malcolm
3/1/2016 6:08:16 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> On Tuesday, March 1, 2016 at 5:27:06 PM UTC, Tim Rentsch wrote:
>> What I am looking for is David Brown's reasons, either objective
>> or subjective, that he never likes using the comma operator.  My
>> hope is that at least some of those reasons will be objective,
>> because then I expect to learn something.
>>
> It's hard to make objective claims about human psychology.
> I claimed that humans cannot deal with more than three levels of
> indirection, nesting, parentheses and so on, on the basis that we
> live in a three dimensional world. You can't have a more objective,
> irrefutable observation than that.

Are you being serious?

Your claim that the number of levels if nesting humas can deal with is
tied to the number of apparent spacial dimensions we live in is an
extraordinary claim.  Calling that claim "objective" and "irrefutable"
is complete nonsense.

[...]

-- 
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"
0
Keith
3/1/2016 7:01:08 PM
On Tuesday, March 1, 2016 at 7:01:19 PM UTC, Keith Thompson wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
>
> Your claim that the number of levels if nesting humas can deal with is
> tied to the number of apparent spacial dimensions we live in is an
> extraordinary claim.  Calling that claim "objective" and "irrefutable"
> is complete nonsense.
> 
A three dimensional array is

int cells[width][height][depth];

If we go to 4 dimensions, we can use time as an expedient, but basically we've 
run out of things a human can visualise.

Now a triple pointer

Cell ***cptr;

is how we pass about that structure by indirection, allowing for ragged entries.
it follows that

Cell ****cptr; is too much.

Now parentheses are another notation for nesting, which is the same as multiple
levels of indirection. If we have a struct node, with a child member, node->child
ppints to the child, node->child->child points to the grandchild, and node->child->
child->child points to the great grandchild. Then we run out of English words,
we just add "great". So again, it's three levels.

Try using "next" and "child" and combinations, such that node->next = "brother",
node->next->next = '2nd brother", node->next->child = "nephew" and so
on. See how complicated an expression you can parse and still get the right
answer, without resorting to strategies like counting.

However the irrefutable claim is that the world has three dimensions.

A physicist will now attack.
0
Malcolm
3/1/2016 7:37:49 PM
Keith Thompson <kst-u@mib.org> writes:

> Your claim that the number of levels if nesting humas can deal with is
> tied to the number of apparent spacial dimensions we live in is an
> extraordinary claim.  Calling that claim "objective" and "irrefutable"
> is complete nonsense.

Keith, its Malcolm...  Making, and the defending (frequently very badly)
extraordinary unsupportable idiotic claims is pretty much his defining
tendency.
0
Gareth
3/1/2016 7:56:42 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> On Tuesday, March 1, 2016 at 7:01:19 PM UTC, Keith Thompson wrote:
>> Your claim that the number of levels if nesting humas can deal with is
>> tied to the number of apparent spacial dimensions we live in is an
>> extraordinary claim.  Calling that claim "objective" and "irrefutable"
>> is complete nonsense.
>> 
> A three dimensional array is
>
> int cells[width][height][depth];
>
> If we go to 4 dimensions, we can use time as an expedient, but basically we've 
> run out of things a human can visualise.

That matters only if the array is visualized as a physical shape in
three-dimensional space.  Not everything is like that.

> Now a triple pointer
>
> Cell ***cptr;
>
> is how we pass about that structure by indirection, allowing for ragged entries.
> it follows that
>
> Cell ****cptr; is too much.

A claim with nothing to back it up.

> Now parentheses are another notation for nesting, which is the same as multiple
> levels of indirection. If we have a struct node, with a child member, node->child
> ppints to the child, node->child->child points to the grandchild, and node->child->
> child->child points to the great grandchild. Then we run out of English words,
> we just add "great". So again, it's three levels.

And that's tied to the number of spacial dimensions?  Riiight.

> Try using "next" and "child" and combinations, such that node->next = "brother",
> node->next->next = '2nd brother", node->next->child = "nephew" and so
> on. See how complicated an expression you can parse and still get the right
> answer, without resorting to strategies like counting.

You've repeated your claim but offered no evidence.

> However the irrefutable claim is that the world has three dimensions.

Nope.  But even if that were true, *your* claim is that there is a
fundamental relationship between the number of spacial dimensions and
the number of nesting levels humans can handle.  Even if both numbers
happened to be 3, I see no reason to believe that they're connected.

I live in a house, on a street, in a neighborhood, in a city, in a
county, in a state, in a country, on a continent, on a planet.  Please
don't presume to tell me that's beyond my comprehension.

> A physicist will now attack.

A physicist would probably just chuckle.

-- 
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"
0
Keith
3/1/2016 8:15:06 PM
On Tuesday, March 1, 2016 at 8:15:18 PM UTC, Keith Thompson wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

>> Try using "next" and "child" and combinations, such that
>> node->next = "brother", node->next->next = '2nd brother", 
>> node->next->child = "nephew" and so on. See how complicated 
>> an expression you can parse and still get the right answer, 
>> without resorting to strategies like counting. 

> You've repeated your claim but offered no evidence. 
>
I've proposed an experiment that you could perform, without a
huge amount of resources. Then you can see whether or not
I'm right.

> Nope.  But even if that were true, *your* claim is that there is a
> fundamental relationship between the number of spacial dimensions and
> the number of nesting levels humans can handle.  Even if both numbers
> happened to be 3, I see no reason to believe that they're connected.
> 
A 2D array is a 1D list of 1D arrays, so nesting. And arrays with
three levels of nesting are intimately connected to models of
solids. 

0
Malcolm
3/1/2016 8:44:24 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> On Tuesday, March 1, 2016 at 7:01:19 PM UTC, Keith Thompson wrote:
>> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
>>
>> Your claim that the number of levels if nesting humas can deal with is
>> tied to the number of apparent spacial dimensions we live in is an
>> extraordinary claim.  Calling that claim "objective" and "irrefutable"
>> is complete nonsense.
>> 
> A three dimensional array is
>
> int cells[width][height][depth];
>
> If we go to 4 dimensions, we can use time as an expedient, but basically we've 
> run out of things a human can visualise.
>
> Now a triple pointer
>
> Cell ***cptr;
>
> is how we pass about that structure by indirection, allowing for ragged entries.

Something I missed before: given your declaration

    int cells[width][height][depth];

a Cell*** (what is type Cell anyway?) cannot be used with the array
"cells".  You're mixing up actual multidimensional arrays (which are
just arrays of arrays) with pointer-based data structures.

> it follows that
>
> Cell ****cptr; is too much.

Personally I have some trouble with Cell*** or int*** -- unless there's
enough context for it to make sense.  The dividing line between
"obvious" and "difficult" isn't between 3 and 4; it's probably somewhere
between 2 and 3 without context, or perhaps substantially higher with
enough context.  Typedefs can sometimes be helpful.

[...]

-- 
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"
0
Keith
3/1/2016 9:10:12 PM
On 01/03/16 18:26, Tim Rentsch wrote:
> Ian Collins <ian-news@hotmail.com> writes:
>
>> Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>>
>>>> On 18/02/16 17:35, Tim Rentsch wrote:
>>>>> David Brown <david.brown@hesbynett.no> writes:
>>>>>
>>>>>> On 28/11/15 23:39, Ben Bacarisse wrote:
>>>>>>> [giving an example re-writing]
>>>>>>>
>>>>>>>         for (int i = 0; i < nb; i++, ch <<= 6)
>>>>>>>              ch += (unsigned char)*utf8++;
>>>>>>
>>>>>> I never like using the comma operator.  [...]
>>>>>
>>>>> Is there some sort of underlying reasoning that motivates that
>>>>> reaction?  Or is it just personal bias?
>>>>
>>>> I think it makes code (such as the example above) less clear, and it
>>>> makes it harder to be sure that the code is correct.
>>>
>>> This sentence is one of those statements that doesn't really say
>>> anything.  Whether you like something is a subjective statement.
>>> Whether you think something is clear, or hard to understand, is a
>>> subjective statement.  What I'm hoping for is some sort of
>>> objective reasoning, not just (re-)statements of personal opinion.
>>
>> Surely clarity is in the eye of the beholder and is therefore
>> subjective?  If you are looking for an objective definition of code
>> clarity, you are on a fools errand.
>
> What I am looking for is David Brown's reasons, either objective
> or subjective, that he never likes using the comma operator.  My
> hope is that at least some of those reasons will be objective,
> because then I expect to learn something.  Conversely, if all of
> them are purely subjective, I don't learn anything.  Saying he
> doesn't like it, he thinks it makes code less clear, he thinks it
> makes it harder to read, he thinks it makes code less obvious
> (which he did not say, but just as an example), etc, all amount
> to the same thing from my point of view - they might tell me
> something about David Brown, but they don't tell me anything
> about anyone else or inherent in the comma operator itself.

I posted some reasons in a different reply.  I presume you'll get to it 
sooner or later - and I hope it gives you some insights into why I 
dislike the comma operator.  In the end, it is a dislike - a subjective 
view - but in my mind at least there are some solid reasons for the dislike.

>
> Incidentally, I believe the issue raised in your first sentence
> is a larger and more complicated topic than the question itself
> suggests, but since it doesn't really bear on my response I will
> leave that discussion for another day.
>

0
David
3/1/2016 10:00:07 PM
On 01/03/16 19:08, Malcolm McLean wrote:
> On Tuesday, March 1, 2016 at 5:27:06 PM UTC, Tim Rentsch wrote:
>>
>> What I am looking for is David Brown's reasons, either objective
>> or subjective, that he never likes using the comma operator.  My
>> hope is that at least some of those reasons will be objective,
>> because then I expect to learn something.
>>
> It's hard to make objective claims about human psychology.
> I claimed that humans cannot deal with more than three levels of
> indirection, nesting, parentheses and so on, on the basis that we
> live in a three dimensional world. You can't have a more objective,
> irrefutable observation than that. But some people simply said that,
> no problem, they can visualise the relationships. So there's no
> real answer to that, other than setting up experiments, which are
> notoriously difficult to get right.

The first claim is that "humans cannot deal with more than three levels 
of indirection, nesting, parentheses, and so on".  This is clearly and 
obviously false, as anyone who has used more than three levels of 
anything can testify.  I won't disagree that going to more than three 
levels of many things gets disproportionally harder than using three or 
less - an expression with more than three levels of parenthesis is 
likely to be quite hard to follow.  But I disagree that there is a fixed 
line, or that the line would be at "three" on many different things.

And certainly it is not an objective or irrefutable claim, nor would it 
be /that/ hard to quantify experimentally.


The second claim is that we live in a three dimensional world.  In some 
important aspects, that is true - we often deal with x, y, and z spatial 
coordinates.  But we spend a significant amount of our time in two 
dimensions - writing on a page, things on a computer screen.  And 
sometimes we think in one dimension - the time axis for music. 
Sometimes we think in four dimensions - position in space combined with 
time.  Sometimes we think in six dimensions - position in space combined 
with three rotational angles.  There are many combinations.

Personally, I used to enjoy playing four-dimensional knots-and-crosses 
at school - some people found it hard, other people found it quite natural.


Your third claim is that the first claim follows objectively and 
irrefutably from the second claim.  Since the first claim is absolute 
nonsense, and the second claim is at least partially nonsense, there is 
no way the third claim could be true.  And even if the first two claims 
were completely true, there is still not the slightest hint or 
justification for the third claim - coincidence does not imply causation.



0
David
3/1/2016 10:13:20 PM
David Brown <david.brown@hesbynett.no> writes:

> On 25/02/16 01:28, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> On 18/02/16 17:35, Tim Rentsch wrote:
>>>> David Brown <david.brown@hesbynett.no> writes:
>>>>
>>>>> On 28/11/15 23:39, Ben Bacarisse wrote:
>>>>>> [giving an example re-writing]
>>>>>>
>>>>>>       for (int i = 0; i < nb; i++, ch <<= 6)
>>>>>>            ch += (unsigned char)*utf8++;
>>>>>
>>>>> I never like using the comma operator.  [...]
>>>>
>>>> Is there some sort of underlying reasoning that motivates that
>>>> reaction?  Or is it just personal bias?
>>>
>>> I think it makes code (such as the example above) less clear, and it
>>> makes it harder to be sure that the code is correct.
>>
>> This sentence is one of those statements that doesn't really say
>> anything.  Whether you like something is a subjective statement.
>> Whether you think something is clear, or hard to understand, is a
>> subjective statement.  What I'm hoping for is some sort of
>> objective reasoning, not just (re-)statements of personal opinion.
>
> It is going to be impossible to get a good, objective basis (at
> least with the time and space practical in a Usenet posting) - but
> maybe it is possible to get a little better than a purely
> subjective and very short statement on clarity.

A much longer followup than I expected.  I may rearrange things a
bit to make responding easier.

> Sticking for now with somewhat vague and subjective terms, my
> dislike of the comma operator is because I think it makes code
> harder to read, harder to maintain, easier to misinterpret, and it
> makes the structure of the code less obvious.

These attributes are somewhat more definite than "less clear",
but they have the same fundamental problem, which is I don't know
why you think so.  (I'm also not sure exactly what is meant by
the different terms but I'm skipping over that for now.)  This is
probably the key point and there should be more on that further
on.

> Further, I think it is particularly confusing to those less
> experienced in C - especially because the comma is used in a
> variety of other contexts in C.

To me this is a non-argument.  Of course people who are not
familiar with some feature of C won't understand how it works.
If it were some weird corner of the language, like being able to
use i[a] in place of a[i], this kind of reaction might be
appropriate, but that doesn't apply to one whole feature of the
language, like the comma operator.

> [...] Let me also be clear that I said "I never like using the
> comma operator".  I think it /can/ be appropriate in some
> circumstances.  [..some examples..]

If your original statement is wrong, probably the first thing you
should do is figure out what is right, and say that.  (I can't
tell for sure whether you are correcting your earlier statement or
just adding additional information.)  What is the difference
between liking something and thinking it is or can be appropriate?
That's really more of a rhetorical question;  exactly what is not
as important as why.

> For reference, Wikipedia has some examples at
> <https://en.wikipedia.org/wiki/Comma_operator>
>
> Now, you might well argue that most of "examples" section are poor
> examples of the use of comma operators -

It seems obvious that these are there to explain the syntax rules
and semantics of the comma operator, not to show good uses or
provide motivation for using it.

> but I think it is telling
> that at least one of these examples doesn't compile, and even
> after correcting it the result is different from that given in the
> comments.

That's just Wikipedia.  There's no way of knowing who wrote that,
or what prompted them to write it.  (I guess in theory one could
paw back through the edit history, but that is likely to be a
pointless exercise.)  The examples being bad says something about
Wikipedia's editing process but nothing substantial about C.

>>> When looking at
>>> a loop, it is important to understand the entry state, the iteration,
>>> and the exit condition in order to be confident that it does what you
>>> want.
>>
>> Sure.
>>
>>> Making any of these parts unnecessarily complicated hinders that
>>> analysis.
>>
>> Same problem as the first sentence - "unnecessarily complicated"
>> is a subjective measure.
>
> Let me try to be a little more concrete.  In a loop, if you have a
> single variable that is initialised at the start of the loop, that
> has a simple exit condition, and that makes strictly monotonic
> progress towards that exit, then it becomes very simple to see how
> the loop works and that it will finish correctly.  Anything beyond
> that makes the loop control more complicated - the loop's control
> is no longer as obvious.  Thus things that are not strictly part
> of the loop's control should not (IMHO) be placed in the
> controlling expressions.

This is just another way of saying what you said in the first
place.  It doesn't add any extra information.  Depending on one's
point of view it is either just a circular restatement or it begs
the question.

> Look at this example (from the Wikipedia page) :
>
> void rev(char *s, size_t len)
> {
>     char *first;
>     for (first = s, s += len - 1; s >= first; --s)
>         putchar(*s);
> }
>
> The pointer "first" is not changed as part of the loop control.
> Putting its initialisation there does nothing except make it
> /look/ like it is part of the loop control until you read more
> carefully.

This isn't a good example.  This example is given to illustrate
the idiom, not to argue for or motivate its use.  Articles on
Wikipedia are meant to report, not to advocate.

> I simply cannot see any benefit to it compared with [alternatives]:

None of these help, because you chose a poor example to start with.

> To my reading, it is more obvious how the loop control works here.

Here is that key point again...more below.


>>> To me, the "ch <<= 6" part should not be part of the loop
>>> control, but inside the loop body.
>>
>> You think that.  The person who wrote it may think of it as being
>> part of the iteration.  Do you think it is _never_ appropriate
>> to write loops that have multiple iteration actions?  And more
>> importantly, if you do, what reasoning explains that reaction?
>
> I think it is rare that multiple iteration actions are appropriate
> - but I would not go as far as to say "never".  And I think it is
> rarer that the multiple independent iteration actions /need/ to be
> part of the controlling expression.

Yes, more of the same.  Just another way of saying what you said
before.  This doesn't tell me anything.

> [a for() loop can be transformed into a while() loop]
>
> But it might be best (again, in my subjective value of "best")
> left as a while loop.

Again, more of the same.  This tells me what you (might) think but
nothing about why you think it.

> C allows code to be written in a very compact way.  Sometimes
> that's fine, but I generally prefer a style that does one thing at
> a time, one line at a time.  If there are two variables that are
> iterated in a loop, I prefer to be able to say "/there/ is the
> line that does Ittr1, and /there/ is the line that does Ittr2".
> (It is not a hard and fast rule - I'll write "*p++ = *q++;" where
> appropriate.)

Same comment as the last one.

>>> I also object to the comma operator in general because it does a
>>> strange thing - it evaluates an expression, then ignores the result,
>>> while being part of a bigger expression.  Obviously you often ignore
>>> the results of an expression as expression statements.
>>
>> I don't know why you think of it as strange.  Expressions in the
>> first and third clauses of a 'for()' clause are executed purely
>> for effect and not for value, but they are expressions, not
>> statements.  Having multiple actions in those places is not very
>> much different than having multiple statements in a block.
>
> The whole "for" statement in C is a little strange, in that the
> first and third clauses must be expressions, but they are usually
> expressions that you would more commonly use as statements in
> other parts of the code.  I guess the fundamental point here is
> that I think it is strange that assignment (and other assignment
> operators) are expressions in C, rather than statements.

So your reaction to comma comes partly out of a personal bias
against assignment being an expression?

>>> But with the
>>> comma operator, I see no advantages in write "x = y, z;" instead of
>>> "y; x = z;".
>>
>> (Corrected to "x = (y, z);".)  There are several.  First the
>> context may not allow writing a statement, but would allow use
>> of a comma operator.  Most commonly this situation occurs with
>> loops or if()'s, but may occur other places (eg, expressions in
>> an initializer).  
>
> Certainly there are situations where you can use a comma operator
> to do multiple things but where statements are not allowed.  The
> question is not whether you /can/ use a comma to combine things in
> an initialiser or an "if" condition - the question is whether or
> not it is /advantageous/.  You can write:
>
>     if (x = getX(), x > 10) ...
>
> but you can also write:
>
>     x = getX();
>     if (x > 10) ...
>
> I don't see any good reasons to prefer the former version, and I
> see the functionality of the second version as clearer.  But I
> accept that there may be circumstances in which the balance is
> different (and obviously different programmers have different
> views on the clarity and balance).

The balance of what?  The point of my question is to understand
what properties you think factor into the question of what the
balance is.

> Can you give a brief example
> of a case where refactoring to remove the comma operator leads to
> clearly worse code (either worse in your opinion, or worse in your
> guess of /my/ opinion).

Certainly I can, but to what purpose?  I have no desire to argue
over whose opinion is better.  The question is what qualities,
or factors, or properties, or aspects, or principles, play an
objective role is assessing which alternatives are acceptable or
not.

>> Second the context may allow multiple actions
>> to be written as statements but there is some sort of collateral
>> benefit (eg, alignment of parallel constructions) to write those
>> using a comma operator instead.  
>
> Again, I have a hard time imagining real cases where a comma
> operator version is better than one without.  But if there are
> such cases, then I can agree that the benefits of clearer code
> layout could well outweigh my objections to the comma operator.

This doesn't tell me anything - not about your objections, not
about what constitutes clearer code.  It says nothing.

>> Third, in some cases a series
>> of simple expressions could be written as statements, but
>> instead comma operators are used to indicate a conceptual
>> grouping that the author considers it useful to express.  
>
> I think such grouping could be better achieved by other means -
> blank lines above and below the group, a block, comments, etc.

Again, this doesn't tell me anything.  I know that you prefer to
avoid use of comma operators.  Saying "another way is better" is
just a different way of saying the same thing.

>> The
>> third case has an analogy in regular English with semicolon.  In
>> most cases sentences are written as stand-alone units and ended
>> with a dot;  in some cases though it helps to join two related
>> sentences with a semicolon.  The use of comma operators is
>> very much (in certain cases) just like the use of semicolons
>> in regular prose.  Certainly all C programs can be written
>> without using any comma operators, just as all monographs can be
>> written without using any semicolons.  But making use of comma
>> operators (and semicolons) allows more faithful expression of
>> the author's intent.  Surely there is some value in that.
>
> Certainly there is value in making the author's intent clear.
> There are always many factors involved if one were to try to
> calculate some sort of "clarity rating" for a piece of code.  I
> am just trying to explain why - for me - the comma operator
> would get a high negative weighting in such a calculation.
> [..some exceptions noted..]

My problem is you haven't really explained why, just said the
same things over again using different words.

>>> And for anyone familiar with languages with a more natural use of
>>> comma, such as Python, the C comma operator is confusing.  In
>>> Python, to swap a and b you write "a, b = b, a".  In Python, this
>>> means replace the objects a and b with b and a respectively.  In
>>> C, this means "take a, evaluate for side-effects, then throw the
>>> result away.  Evaluate b = b for side-effects, and throw the
>>> result away.  Evaluate a for side-effects again, and throw away
>>> the result".
>>
>> I program in Python, and also other languages where comma means
>> something different than it does in C.  I have no trouble
>> keeping the different uses straight, nor have I ever seen such
>> confusion in any other experienced programmer.  In my view
>> anyone who remains confused on this sort of minor point either
>> shouldn't be programming in the first place, or just isn't
>> trying.  Do you have any kind of response to that statement?
>
> The obvious response is that not everyone is as experienced a
> programmer.  And regardless of experience, not every programmer is
> as good.  And regardless of experience and ability, not every
> programmer covers the same fields or has worked with the same
> range of coding.  There are countless C programmers who have
> worked for decades, but who would find any use of the comma
> operator strange and unfamiliar.  Just because someone is an
> "experienced programmer", does not mean they are so used to all
> features of C that the meanings are obvious to them.

This argument is pure applesauce.  Anyone who has been programming
in C for 20 years or more has encountered comma operators and
knows what they mean, even if they don't use them in their own
code.  For novices who have not yet seen the comma operator,
explaining it takes, what, 15 minutes?  Give me a break.

>>> "Do not use the comma operator" is a rule that is common in
>>> programming standards, so I am not alone in my dislike for it.
>>
>> I realize that's true, but that's not a reason.  I'm looking for
>> something more than just a statement of opinion, and there can be
>> collective opinion just as there is individual opinion.  I don't
>> remember ever seeing any rationale for not using comma operators
>> that didn't boil down to just opinion or circular explanations.
>> This motivates me to ask about it.
>
> I think that if you take /any/ rules about style or choice of
> features to use, and boil them long enough, you will end up with
> opinion and circular explanations at the bottom.

I find this statement quite incredible.  Of course there will be
some subjective weighting applied to the various factors to come
up with an overall reaction or judgment.  But the idea that there
is nothing other than purely personal opinion that plays a role
in forming those reactions is..  I don't even know what word to
use here.. silly? ridiculous? naive?  Undoubtedly some people
operate that way.  Others do not.

> But I hope that
> I have now given you at least some hints of a rationale for my
> opinions here.  [...]

Your comments remind me of Abraham Lincoln's famous book review:
"People who like this sort of thing will find this the sort of
thing they like."  Maybe not zero information content, but pretty
darned close.

I have a hypothesis, or maybe two, and a suggestion.  Hypothesis
first:  what you mean by "unclear" or "less clear" is "written
differently than how you would write it."  If it's written in a
way that's familiar to you and similar to how you would write it
yourself then it's clear, and otherwise it isn't.  (That isn't
meant to be as black and white as it is stated, so please don't
take it that way.)  Over the years you have developed various
coding habits, and those habits usually don't employ the comma
operator, so any code that uses it looks somehow strange and hard
to understand.  To some extent it is a self-fulfilling prophecy.

The suggestion is that you make more of an effort to distinguish
and separate out objective measures from subjective ones.
Related to this suggestion is to distinguish (and label as such)
statements of fact and statements of opinion.  I think you are
used to operating in a mode where the only thing that "counts"
(written in quotes because I'm not sure what "counting" means) is
opinion.  I think it might be better for you, and also people you
work with, if you could activate both modes and be able to switch
back and forth between them with some degree of ease.  And to
bring this around to the original point, that would also make it
easier for me (and other interested parties, assuming there are
any) to get answers to questions like the one that started this
discussion.

I'm sorry this response is so long.  I didn't have enough time to
make it shorter.
0
Tim
3/1/2016 10:38:21 PM
On 01/03/16 23:38, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:

<snip>

Although I snipped almost all of your reply, I have read it all and
considered it.  But I believe we are at an impasse - my intention was to
give some rationale for why I avoid the comma operator.  You argue that
my dislike is purely subjective.  I don't think there is any way of
convincing you otherwise.  We could of course conduct surveys of
programmers, programs, statistics on the causes of bugs, etc., but even
if that showed scientifically that the comma operator was a terrible
source of bugs and confusion, that would be after the fact - I cannot
use future results to justify past opinions.

My thoughts on what is "clear" are strongly tied to my work.  "Code
clarity" means "do my colleagues understand the code, and see it is
correct?".  Are my customers happy?  How is the code from my suppliers?
  My programming world is different from yours - small systems embedded
programming is a niche area, and people write code in different ways
from other types of programming.  (Of course, one can say exactly the
same thing about many other fields of programming - games programming is
different from database programming or Linux kernel programming or
whatever.)  In my world, the comma operator is practically non-existent
- it is rarer than "malloc", which is usually banned outright in most
programs I deal with.

You say I define "clarity" in terms of how I would write code?  Of
course I do - the concepts are intertwined.  When I write code, I try to
write clearly.  The concepts are not identical - code can be clear even
if it is written in a different way from how I would have approached it.

And remember that the background for this discussion was that I said "I
never like using the comma operator".  No matter what other influences
and reasoning I have for that, part of it is going to be "I don't like
using the comma operator because I don't use the comma operator".  Maybe
it is even the major part - though it stretches a good deal wider than
just me.  Small systems embedded programmers should not use the comma
operator, because small systems embedded programmers don't use the comma
operator.

Anyway, I think this line of discussion is closed for now.  I thank you
for your time, and forcing me to think a little about my opinions here,
but I doubt if we will get much more out of another turn around the same
circle.

mvh.,

David




>> But I hope that
>> I have now given you at least some hints of a rationale for my
>> opinions here.  [...]
> 
> Your comments remind me of Abraham Lincoln's famous book review:
> "People who like this sort of thing will find this the sort of
> thing they like."  Maybe not zero information content, but pretty
> darned close.
> 
> I have a hypothesis, or maybe two, and a suggestion.  Hypothesis
> first:  what you mean by "unclear" or "less clear" is "written
> differently than how you would write it."  If it's written in a
> way that's familiar to you and similar to how you would write it
> yourself then it's clear, and otherwise it isn't.  (That isn't
> meant to be as black and white as it is stated, so please don't
> take it that way.)  Over the years you have developed various
> coding habits, and those habits usually don't employ the comma
> operator, so any code that uses it looks somehow strange and hard
> to understand.  To some extent it is a self-fulfilling prophecy.
> 
> The suggestion is that you make more of an effort to distinguish
> and separate out objective measures from subjective ones.
> Related to this suggestion is to distinguish (and label as such)
> statements of fact and statements of opinion.  I think you are
> used to operating in a mode where the only thing that "counts"
> (written in quotes because I'm not sure what "counting" means) is
> opinion.  I think it might be better for you, and also people you
> work with, if you could activate both modes and be able to switch
> back and forth between them with some degree of ease.  And to
> bring this around to the original point, that would also make it
> easier for me (and other interested parties, assuming there are
> any) to get answers to questions like the one that started this
> discussion.
> 
> I'm sorry this response is so long.  I didn't have enough time to
> make it shorter.
> 

0
David
3/2/2016 10:02:33 AM
David Brown <david.brown@hesbynett.no> writes:

> On 01/03/16 23:38, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
<snip>
> My thoughts on what is "clear" are strongly tied to my work.  "Code
> clarity" means "do my colleagues understand the code, and see it is
> correct?".  Are my customers happy?  How is the code from my suppliers?
>   My programming world is different from yours - small systems embedded
> programming is a niche area, and people write code in different ways
> from other types of programming.

So are you saying that a sub-culture just happens to have grown up in
this field that sees the comma operator in some way inimicable to
clarity?  You can't be suggesting that there is something about small
systems themselves that contributes to comma operators being unclear.
Or is it that clarity is somehow more important in small systems so the
detrimental effect (real or imagined) of comma operators is more
significant?

I wonder if you have tried putting a comma operator into your code (not,
of course, as in the Wikipedia page!) to see what happens.  Would your
colleagues actually be confused by it (even momentarily), or would they
suggest it be removed because "we don't do that sort of thing" (i.e. it
contravenes an explicit or implicit coding standard)?

> [...]  In my world, the comma operator is practically non-existent
> - it is rarer than "malloc", which is usually banned outright in most
> programs I deal with.

You can't be saying that the two are somehow the same can you?  malloc
is often ruled out for perfectly well-understood run-time consequences
and not for any reasons to do with clarity of expression.

<snip>
> Anyway, I think this line of discussion is closed for now.

Oh, sorry.  I find discussions of style very interesting though often
not very productive.  Feel free to ignore this.

<snip>
-- 
Ben.
0
Ben
3/2/2016 1:27:33 PM
On 01/03/16 20:15, Keith Thompson wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

<snip>

>> However the irrefutable claim is that the world has three dimensions.
>
> Nope.  But even if that were true, *your* claim is that there is a
> fundamental relationship between the number of spacial dimensions and
> the number of nesting levels humans can handle.  Even if both numbers
> happened to be 3, I see no reason to believe that they're connected.
>
> I live in a house, on a street, in a neighborhood, in a city, in a
> county, in a state, in a country, on a continent, on a planet.  Please
> don't presume to tell me that's beyond my comprehension.

Of course not, but I'm not sure whether that's a good illustration of a 
multidimensional array. The point about dimensions is that they are (and 
I have to be careful how I use this word!) orthogonal to each other, 
rather than hierarchical (although of course the dimension number could 
be considered an hierarchy in some sense).

Perhaps a better example of a multidimensional space would be something 
like this:
[clockspeed][num usb ports][colour][network card speed][hard disk size]

Okay, so that 5D array would be fairly sparse, but that doesn't matter 
particularly. What /does/ matter is that it isn't even remotely 
difficult to envisage five independent facts about an object.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/2/2016 3:27:44 PM
On 02/03/16 14:27, Ben Bacarisse wrote:
> David Brown <david.brown@hesbynett.no> writes:
> 
>> On 01/03/16 23:38, Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
> <snip>
>> My thoughts on what is "clear" are strongly tied to my work.  "Code
>> clarity" means "do my colleagues understand the code, and see it is
>> correct?".  Are my customers happy?  How is the code from my suppliers?
>>   My programming world is different from yours - small systems embedded
>> programming is a niche area, and people write code in different ways
>> from other types of programming.
> 

(This whole topic seems to have grown well out of proportion from a
single out-of-context comment I made.  I really don't think the comma
operator is so important.  In my mind, it is something that happens to
be legal C, but is of no particular use and can be confusing - so I
don't use it.  The same could be said of using "OOOO0O0O" and "OOO0OO0O"
as a variable identifiers - though I doubt if I would be asked to
justify complaining that these are unclear.)

> So are you saying that a sub-culture just happens to have grown up in
> this field that sees the comma operator in some way inimicable to
> clarity?  You can't be suggesting that there is something about small
> systems themselves that contributes to comma operators being unclear.
> Or is it that clarity is somehow more important in small systems so the
> detrimental effect (real or imagined) of comma operators is more
> significant?

I think that last sentence is significant here.  I do think there is a
"sub-culture" in embedded programming where clarity (real or imagined,
as you say) is given greater emphasis than in many other areas of
programming.  It is not the only field of programming with such an
emphasis, and not everyone doing embedded programming follows the same
rules, guidelines, or emphases, but there is at least a sub-sub-culture
in embedded development that put a great deal of effort into making sure
that not only is their code correct, but that it can be easily seen to
be correct, and that they can demonstrate that they have made this
effort.  In some embedded systems, if something goes wrong in the code
lives or significant money can be at risk.  And if something goes wrong,
the programmer and/or development company can be held liable if they
were considered negligent.

Thus in Europe, for any software involved in car safety, there is the
MISRA coding standard.  This involves at least some rules that are
unlikely to be popular in general C programming - it advises against the
use of types like "int", for example, and requires that dynamic memory
shall not be used.  This is what it says about the comma operator:

Rule 12.3 The comma operator should not be used
Category Advisory
Analysis Decidable, Single Translation Unit
Applies to C90, C99

Rationale
	Use of the comma operator is generally detrimental to the
	readability of code, and the same effect can usually be
	achieved by other means.

Example
	f ( ( 1, 2 ), 3 );
	/* Non-compliant - how many parameters? */

	The following example is non-compliant with this rule and other
	rules:

	for ( i = 0, p = &a[ 0 ]; i < N; ++i, ++p )
	{
	}




> 
> I wonder if you have tried putting a comma operator into your code (not,
> of course, as in the Wikipedia page!) to see what happens.  Would your
> colleagues actually be confused by it (even momentarily), or would they
> suggest it be removed because "we don't do that sort of thing" (i.e. it
> contravenes an explicit or implicit coding standard)?
> 

I haven't tried it, but perhaps I will at some point.

>> [...]  In my world, the comma operator is practically non-existent
>> - it is rarer than "malloc", which is usually banned outright in most
>> programs I deal with.
> 
> You can't be saying that the two are somehow the same can you?  malloc
> is often ruled out for perfectly well-understood run-time consequences
> and not for any reasons to do with clarity of expression.

I don't mean that rules banning (or at least restricting) malloc and the
comma operator will have the same justification - obviously that is not
the case.  I mean that they can often be found in the same type of
coding guidelines, aimed at the same type of programs.

Some other MISRA rules that are justified by "readability" include
advising against the use of "++" or "--" in expressions with side
effects other than the increment or decrement (no "a = b++;", for
example) or using the result of an assignment operator (no "a = b = c;").

As to what "readability" really means, I think we have established that
it is a rather subjective concept.  But my point here is that it is not
my view alone - there is at least a "sub-culture" with similar views.

> 
> <snip>
>> Anyway, I think this line of discussion is closed for now.
> 
> Oh, sorry.  I find discussions of style very interesting though often
> not very productive.  Feel free to ignore this.
> 

I am very bad at ignoring posts!  As long as there is at least some new
points, I am quite happy to continue if someone finds it interesting.
All I want to avoid is another round of:

David: I think ...
Tim: /Why/ do you think that?
David: mumble, mumble...
Tim: That's just a personal bias.  Do you have any good reasons?
David: mumble, mumble...
Tim: That's subjective.  Do you have any objective basis?
....



> <snip>
> 

0
David
3/2/2016 3:40:08 PM
David Brown <david.brown@hesbynett.no> writes:

> My thoughts on what is "clear" are strongly tied to my work.  "Code
> clarity" means "do my colleagues understand the code, and see it is
> correct?".

I think there's one objective way in which the comma operator is
"unclear", and it bears on this "do my colleagues understand" question.
My programming colleagues, on the whole do the bulk of their work in
languages other than C, but must right code that interfaces with C.  To
this end, it is sometimes necessary for them to read and comprehend C
code (perhaps the documentation is lacking in some corner case.)

The comma operator has no equivalent (that I know of) in any other
language (besides those with explicit c compatibility).  Unlike much C
syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
comma operator is a construct that no-one who is not a C expert will
readily understand.
0
Gareth
3/2/2016 8:28:17 PM
On Wednesday, March 2, 2016 at 3:27:55 PM UTC, Richard Heathfield wrote:
>
> Perhaps a better example of a multidimensional space would be something 
> like this:
> [clockspeed][num usb ports][colour][network card speed][hard disk size]
> 
> Okay, so that 5D array would be fairly sparse, but that doesn't matter 
> particularly. What /does/ matter is that it isn't even remotely 
> difficult to envisage five independent facts about an object.
>
Exactly. Normally such a sparse array would be represented as a 2D array

Computer clockspeed Nusb colour network disksize

ZX81       2MHz       0    no    400 baud  1.4MB

BBC        4Mhz       0    yes   1200 baud  1.4MB

386        25Mhz      0    no    3,600 baud  40MB


and so on.

You could represent as points in 5 dimensional space, but then it's
hard to visualise and a lot of space is wasted. 
0
Malcolm
3/2/2016 10:41:27 PM
On 02/03/16 22:41, Malcolm McLean wrote:
> On Wednesday, March 2, 2016 at 3:27:55 PM UTC, Richard Heathfield wrote:
>>
>> What /does/ matter is that it isn't even remotely
>> difficult to envisage five independent facts about an object.
>>
> Exactly. Normally such a sparse array would be represented as a 2D array
>

It is possible to represent /anything/ as a 2D array or even a 1D array, 
but you're missing the point. A 5D array allows me to do this:

for(i = 0; i < imax; i++)
{
   for(j = 0; j < jmax; j++)
   {
     for(k = 0; k < kmax; k++)
     {
       printf("%d\n", arr[i][17][j][k][4]);
     }
   }
}

which would not be /impossible/ with a 2D array (or even a 1D array, but 
would be much less convenient, notationally speaking.

> You could represent as points in 5 dimensional space, but then it's
> hard to visualise and a lot of space is wasted.

Forget spatial dimensions, and the difficulty of visualisation vanishes. 
Think of a dimension as a characteristic that is orthogonal to other 
characteristics, and everything becomes very, very simple.

If you insist on 'dimension' meaning 'one of: height, breadth, width', 
then you miss a great deal of the flexibility of dimensional notation, 
even if we're only talking about spatial dimensions. For example, 
fractal curves have fractional dimensions, which don't make sense in a 
'height/breadth/width' view of dimensionality, but /do/ make sense if 
you take a broader view of what a dimension actually /is/.

Let me give you a slightly different example. Consider a warehouse that 
has ten aisles. Each aisle consists of eight racks. Each rack has four 
levels. Each level is divided into three sublevels vertically, and these 
each have four horizontal divisions. Every division contains five boxes. 
Each box contains an arbitrary number of widgets. The number of these 
widgets can be tracked using an array like this:

widget_count[10][8][4][3][4][5]

That's a six-dimensional array, and it's easy to visualise. QED.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/2/2016 11:35:48 PM
Malcolm McLean wrote:
> On Wednesday, March 2, 2016 at 3:27:55 PM UTC, Richard Heathfield wrote:
>>
>> Perhaps a better example of a multidimensional space would be something
>> like this:
>> [clockspeed][num usb ports][colour][network card speed][hard disk size]
>>
>> Okay, so that 5D array would be fairly sparse, but that doesn't matter
>> particularly. What /does/ matter is that it isn't even remotely
>> difficult to envisage five independent facts about an object.
>>
> Exactly. Normally such a sparse array would be represented as a 2D array

Normally?  Where do you get that from?

In other languages (that support associative arrays) I often use 
structures similar to Richards example above.  One of my applications 
has a JSON blob representing the system's device tree which extends to 
many levels.

-- 
Ian Collins
0
Ian
3/3/2016 3:44:43 AM
On Thursday, March 3, 2016 at 3:44:52 AM UTC, Ian Collins wrote:
> Malcolm McLean wrote:
> > On Wednesday, March 2, 2016 at 3:27:55 PM UTC, Richard Heathfield wrote:
> >>
> >> Perhaps a better example of a multidimensional space would be something
> >> like this:
> >> [clockspeed][num usb ports][colour][network card speed][hard disk size]
> >>
> >> Okay, so that 5D array would be fairly sparse, but that doesn't matter
> >> particularly. What /does/ matter is that it isn't even remotely
> >> difficult to envisage five independent facts about an object.
> >>
> > Exactly. Normally such a sparse array would be represented as a 2D array
> 
> Normally?  Where do you get that from?
> 
> In other languages (that support associative arrays) I often use 
> structures similar to Richards example above.  One of my applications 
> has a JSON blob representing the system's device tree which extends to 
> many levels.
> 
Statistics packages, like R for example.

If you got a list of computers with associated data (name, clock speed, number usb ports, colour, network card speed, hard disk size, etc) then 
what you do is set them up as a "data frame". That's a 2 dimensional
structure, but each column is allowed a different type.

However if you do, say a principal components analysis, or a clustering
based an Euclidean distance, you have to expand to five dimensions,
each row becomes a point in 5D space rather than en entry in a 2D
table.
 
With trees, typically when showing them to the user, you allow nodes 
to be collapsed or expanded, to keep the visual complexity down.
With flat lists, you don't, you present in a scroll window, but only
occasionally do you allow filters (show all entries with the suffix 
..txt).
0
Malcolm
3/3/2016 9:09:11 AM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

> On Friday, February 26, 2016 at 4:30:01 PM UTC, David Brown wrote:
>
>> I don't think the function /is/ undefined.  It has undefined behaviour
>> for certain inputs (null pointer for s, or 0 len), but that is not the
>> same thing as saying the function is "technically undefined".  (Or is it?)
>
> Probably most C functions are in fact undefined for inputs of
> null, INT_MAX, N = 0 / -1, SIZE_MAX, strings longer than INT_MAX,
> NaN, inf, DBL_MIN, x = y + DBL_EPSILON, and so forth.
>
>> I agree that a while loop makes more sense in this case - but that
>> wasn't really the point I was making.
>
> The function is just
>
> void rev(char *s, int (size_t if you must) len)
> {
> while(len--)
>   putchar(s[len]);
> }
>
> that's how any experienced C programmer would write it. [...]

How some experienced C programmers would write it.  Not all.
0
Tim
3/3/2016 4:20:58 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

> On Tuesday, March 1, 2016 at 5:27:06 PM UTC, Tim Rentsch wrote:
>
>> What I am looking for is David Brown's reasons, either objective
>> or subjective, that he never likes using the comma operator.  My
>> hope is that at least some of those reasons will be objective,
>> because then I expect to learn something.
>
> It's hard to make objective claims about human psychology.  I
> claimed that humans cannot deal with more than three levels of
> indirection, nesting, parentheses and so on, on the basis that
> we live in a three dimensional world.  You can't have a more
> objective, irrefutable observation than that. But some people
> simply said that, no problem, they can visualise the
> relationships.  So there's no real answer to that, other than
> setting up experiments, which are notoriously difficult to get
> right.

I think you have misunderstood my comment.  I just want to know
what the reasons are (and whether they are purely subjective, or
otherwise).  I'm not asking for any supporting evidence, I just
want to know what the underlying rationale is.

> Clearly, comma operators can be used to create correct programming
> constructs.  Clearly, C is Turing complete without them.  That's
> the end of the objective observations.  Everything else is "I find
> the syntax difficult, the programs hard to follow".  [...]

I find it astonishing that anyone would say that.  It's clearly
and obviously false.
0
Tim
3/5/2016 6:30:01 PM
David Brown <david.brown@hesbynett.no> writes:

> On 01/03/16 23:38, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>
> <snip>
>
> Although I snipped almost all of your reply, I have read it all
> and considered it.  But I believe we are at an impasse - my
> intention was to give some rationale for why I avoid the comma
> operator.  You argue that my dislike is purely subjective.  I
> don't think there is any way of convincing you otherwise.  We
> could of course conduct surveys of programmers, programs,
> statistics on the causes of bugs, etc., but even if that showed
> scientifically that the comma operator was a terrible source of
> bugs and confusion, that would be after the fact - I cannot use
> future results to justify past opinions.

I see in hindsight that the discussion went off the rails almost
right from the start.  I have to take some of the responsibility
for that;  if I were smarter I would have figured this out
earlier, but oh well.  Anyway let me try to rectify those earlier
shortcomings.

First off my original question was binary, and either answer
would have been okay.  If your answer had been "oh I just don't
like it" that would have answered my question.  Some people don't
like eating broccoli;  there doesn't have to be a reason for
that, they might just not like it.

Second, after we got past the initial binary question, I wasn't
expecting you to justify your rationale.  I don't need to be
convinced that your beliefs are true - I just want to know what
those beliefs are.  This case is one of those where it is
essential to distinguish between statements of belief and
statements of fact.  Saying "I believe code that makes use of
comma operators takes 50% longer to debug" is very different from
saying "Code that makes use of comma operators takes 50% longer to
debug".  Since the purpose (from my point of view) of entering
into the discussion is to find out what your beliefs are, it is
crucial that there be a distinction between which statements are
offered only as statements of belief and which statements are
offered as statements of fact.  More specifically, the distinction
should be both clear in your own mind and plainly evident in the
writing;  otherwise it's hard to know what you are saying.

Third, I haven't done a good job of explaining the difference
between the terms "subjective" and "objective" as I have been
using them.  Basically, an assessment is subjective (or purely
subjective, but let's ignore that refinement for the moment) if
the only way to determine if it holds is to ask someone else
about it.  Conversely, an assessment is objective if it can be
determined reliably by any independent observer.  For example,
"broccoli tastes icky" is a subjective statement, whereas a
statement like "eating broccoli at least once a week increases
the risk of heart attack by 40%" is an objective statement.  Note
that a statement doesn't have to be either true or easy to verify
to be an objective statement;  it just has to be independently
measurable.  Similarly if you say "code that uses comma operators
is hard to read", to me that must be a subjective statement,
because the only way I have to decide if something is -- in your
view -- "hard to read" is to ask you if it is;  you haven't given
any way of measuring the property that could be performed by an
independent observer.  The problem with a subjective statement
is not that it's wrong, but that I don't even know what it is
saying.  And if I don't know what it's saying, I'm right back
at where I started - I don't know why you think what you think.
You see the problem?

> My thoughts on what is "clear" are strongly tied to my work.
> "Code clarity" means "do my colleagues understand the code, and
> see it is correct?".  Are my customers happy?  How is the code
> from my suppliers?  [...] In my world, the comma operator is
> practically non-existent [...]

Some observations (or reactions?) about this.  One, what you mean
by "clear" is therefore not just a property of the code, but
(also) a property of who is oberving it.  Two, there is no way I
would have guessed that this is what you meant.  Three, this
notion of what "clear" means makes it an inherently subjective
measure - I have no way of telling whether code is "clear" without
asking someone else (and maybe even without asking just you).

If at the beginning you had said "I don't like using comma
operators because the people I'm used to working with tend not to
use it and generally don't like it either", then that would have
answered my question.  It gives a definite, objective reason for
your reaction (ignoring the wishy-washiness of "tend" and
"generally", which is not hard to work around).  It isn't easy
necessarily to measure whether the stated condition holds, but in
principle it could be done just by looking at the code and asking
the other people involved.

> You say I define "clarity" in terms of how I would write code?  Of
> course I do - the concepts are intertwined.  When I write code, I
> try to write clearly.  The concepts are not identical - code can
> be clear even if it is written in a different way from how I would
> have approached it.

Taken as a whole this paragraph doesn't make sense.  The idea that
you judge whether something is clear by whether it is written as
you would write it (or expressed in a familiar way) is either true
or false.  It can't be both true and not true.

Also I was surprised by the "Of course I do".  For me that would
have been "Of course I don't".  Naturally if I see code written in
a way that is similar to how I might write it then I am likely
(but not certain!) to think the code is easily understandable, but
the converse doesn't hold.  Looking at code where my reaction is
"oh I would never write it this way" I still can think that the
code is easily understandable.  To some extent I think that a mark
of a good developer is to take in different forms (of expressing
the same functionality) with comparative ease.

> And remember that the background for this discussion was that I
> said "I never like using the comma operator".  No matter what
> other influences and reasoning I have for that, part of it is
> going to be "I don't like using the comma operator because I don't
> use the comma operator".

That may be true in your case.  I don't think it has to be true in
all cases.

> Maybe it is even the major part - though
> it stretches a good deal wider than just me.  Small systems
> embedded programmers should not use the comma operator, because
> small systems embedded programmers don't use the comma operator.

If this is stated as your belief, I accept it as such.  If stated
as a proposition that everyone should agree with, I'm afraid I
would have to object.  However my purpose was only to discover
your beliefs, not argue about them, so we don't have to pursue
the second question.

> Anyway, I think this line of discussion is closed for now.  I
> thank you for your time, and forcing me to think a little about my
> opinions here, but I doubt if we will get much more out of another
> turn around the same circle.

I appreciate your comments and you taking the time to write them.
If there is something you want to say in response please go ahead,
however in writing this I am neither expecting nor not expecting
any response, so it's entirely up to you.
0
Tim
3/5/2016 9:20:09 PM
Gareth Owen <gwowen@gmail.com> writes:

> David Brown <david.brown@hesbynett.no> writes:
>
>> My thoughts on what is "clear" are strongly tied to my work.  "Code
>> clarity" means "do my colleagues understand the code, and see it is
>> correct?".
>
> I think there's one objective way in which the comma operator is
> "unclear", and it bears on this "do my colleagues understand" question.
> My programming colleagues, on the whole do the bulk of their work in
> languages other than C, but must right code that interfaces with C.  To
> this end, it is sometimes necessary for them to read and comprehend C
> code (perhaps the documentation is lacking in some corner case.)

"The people I work with generally have difficulty with the comma
operator when they see it" is (an example of) an objective
measure.  That could be given as a definition of, or an argument
for, what "unclear" is or should mean.  What I'm interested in
though is what the measure is, because that's where the valuable
information is.  Whether we call that "clarity", or "readability",
or "niceness", or something else, is incidental.

> The comma operator has no equivalent (that I know of) in any other
> language (besides those with explicit c compatibility).  Unlike much C
> syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
> comma operator is a construct that no-one who is not a C expert will
> readily understand.

I find this comment very interesting.  In fact there are lots of
languages, and indeed a whole class of languages, that have
similar constructs.  In Algol 68, for example, a parenthesized
sequence of "statements" (speaking loosely) can be used as an
expression for its value.  Thus we might write something like

   int average := (int sum := 0; for i to n do sum +:= f(i) od; sum) / n

This capability is like the comma operator on steroids.  What can
appear as operands of a comma operator is comparatively limited.
By contrast, in "expression languages" like Algol 68 (for some
reason Wikipedia calls these "expression-oriented languages"),
the full gamut of declarations, assignment, sequencing, loops,
conditionals, and who knows what else, can all be part of a
larger expression.

What makes this especially interesting is that I was familiar
with expression languages long before I ever learned C.  For me
the comma operator was just a stripped down version of the more
complete scheme adopted in expression languages.  So when I first
encountered C's comma operator the idea wasn't something new and
unfamiliar, just a simpler variation on something I already knew.
If someone not familiar with the concept of expression languages,
or something like it, first encountered the idea in the form of
the comma operator in C, it would naturally seem somewhat strange
compared to languages like Fortran or Pascal.  Very interesting
possibility.
0
Tim
3/5/2016 10:44:07 PM
On 03/06/16 11:44, Tim Rentsch wrote:
> Gareth Owen <gwowen@gmail.com> writes:
>
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> My thoughts on what is "clear" are strongly tied to my work.  "Code
>>> clarity" means "do my colleagues understand the code, and see it is
>>> correct?".
>>
>> I think there's one objective way in which the comma operator is
>> "unclear", and it bears on this "do my colleagues understand" question.
>> My programming colleagues, on the whole do the bulk of their work in
>> languages other than C, but must right code that interfaces with C.  To
>> this end, it is sometimes necessary for them to read and comprehend C
>> code (perhaps the documentation is lacking in some corner case.)
>
> "The people I work with generally have difficulty with the comma
> operator when they see it" is (an example of) an objective
> measure.  That could be given as a definition of, or an argument
> for, what "unclear" is or should mean.  What I'm interested in
> though is what the measure is, because that's where the valuable
> information is.  Whether we call that "clarity", or "readability",
> or "niceness", or something else, is incidental.

Even in the world of C programming the comma operator is seldom used, at 
least in the code I've seen.  I would go so far as to say that it is 
sufficiently obscure to be avoided or simply forgotten by a large 
percentage of programmers.

For the "my colleagues have difficulty with it" reason alone I consider 
the comma operator hinders code clarity.

-- 
Ian Collins
0
Ian
3/5/2016 11:00:45 PM
On 05/03/2016 22:44, Tim Rentsch wrote:
> Gareth Owen <gwowen@gmail.com> writes:

>> The comma operator has no equivalent (that I know of) in any other
>> language (besides those with explicit c compatibility).  Unlike much C
>> syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
>> comma operator is a construct that no-one who is not a C expert will
>> readily understand.
>
> I find this comment very interesting.  In fact there are lots of
> languages, and indeed a whole class of languages, that have
> similar constructs.  In Algol 68, for example, a parenthesized
> sequence of "statements" (speaking loosely) can be used as an
> expression for its value.  Thus we might write something like
>
>     int average := (int sum := 0; for i to n do sum +:= f(i) od; sum) / n
>
> This capability is like the comma operator on steroids.

It's not the capability that is in question, but more the choice of 
comma. Notice your Algol68 example doesn't use commas. It almost 
certainly doesn't consider the semicolon an operator either.

(Algol68 does sometimes also use commas for questionable purposes, for 
example in some contexts (case-in-out statements for one), commas 
separate sequences of statements/expressions:

   a;b;c, d;e, f;g;h

this looks odd, because in English the use of semicolon and comma would 
be reversed: a,b,c; d,e; f,g,h as semicolon is a stronger separator.)

> What can
> appear as operands of a comma operator is comparatively limited.
> By contrast, in "expression languages" like Algol 68 (for some
> reason Wikipedia calls these "expression-oriented languages"),
> the full gamut of declarations, assignment, sequencing, loops,
> conditionals, and who knows what else, can all be part of a
> larger expression.

Apart from choosing to use comma, C has doesn't really provide enough of 
this generality. So that comma is little used, but when it is, it can 
cause confusion.

-- 
Bartc
0
BartC
3/6/2016 12:05:23 AM
On 05/03/16 23:44, Tim Rentsch wrote:
> Gareth Owen <gwowen@gmail.com> writes:
>
>> The comma operator has no equivalent (that I know of) in any other
>> language (besides those with explicit c compatibility).  Unlike much C
>> syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
>> comma operator is a construct that no-one who is not a C expert will
>> readily understand.
>
> I find this comment very interesting.  In fact there are lots of
> languages, and indeed a whole class of languages, that have
> similar constructs.  In Algol 68, for example, a parenthesized
> sequence of "statements" (speaking loosely) can be used as an
> expression for its value.  Thus we might write something like
>
>     int average := (int sum := 0; for i to n do sum +:= f(i) od; sum) / n
>
> This capability is like the comma operator on steroids.  What can
> appear as operands of a comma operator is comparatively limited.
> By contrast, in "expression languages" like Algol 68 (for some
> reason Wikipedia calls these "expression-oriented languages"),
> the full gamut of declarations, assignment, sequencing, loops,
> conditionals, and who knows what else, can all be part of a
> larger expression.
>
> What makes this especially interesting is that I was familiar
> with expression languages long before I ever learned C.  For me
> the comma operator was just a stripped down version of the more
> complete scheme adopted in expression languages.  So when I first
> encountered C's comma operator the idea wasn't something new and
> unfamiliar, just a simpler variation on something I already knew.
> If someone not familiar with the concept of expression languages,
> or something like it, first encountered the idea in the form of
> the comma operator in C, it would naturally seem somewhat strange
> compared to languages like Fortran or Pascal.  Very interesting
> possibility.
>

One thing to consider here is if we are talking about "other people", we 
need to think about their likely knowledge and experience.  It may well 
be that Algol 68 has a "super comma" capability.  But how many C 
programmers have had any experience of Algol?  I have no statistics on 
hand, but I suspect Algol was mainly of historic interest before most 
current C programmers were born.  So for you, as an Algol programmer 
when you learned C, the comma operator came easily.  For most C 
programmers, who are more likely to have experience with Java, Basic, or 
perhaps C++ (if any language at all), I expect that the comma operator 
is something new and obscure.

0
David
3/6/2016 11:50:50 AM
On 06/03/2016 11:50, David Brown wrote:

> For most C
> programmers, who are more likely to have experience with Java, Basic, or
> perhaps C++ (if any language at all), I expect that the comma operator
> is something new and obscure.

Maybe the comma operator could be used like this:

#define last(...) (__VA_ARGS__)

  last(a,b,c)

Then it no longer need be thought of as an operator, but as a more 
familiar separator. The comma-operator just becomes another gimmick used 
by the macro system.

-- 
Bartc
0
BartC
3/6/2016 12:25:51 PM
W dniu niedziela, 6 marca 2016 12:50:58 UTC+1 u=C5=BCytkownik David Brown n=
apisa=C5=82:
> On 05/03/16 23:44, Tim Rentsch wrote:
> > Gareth Owen <gwowen@gmail.com> writes:
> >
> >> The comma operator has no equivalent (that I know of) in any other
> >> language (besides those with explicit c compatibility).  Unlike much C
> >> syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
> >> comma operator is a construct that no-one who is not a C expert will
> >> readily understand.
> >
> > I find this comment very interesting.  In fact there are lots of
> > languages, and indeed a whole class of languages, that have
> > similar constructs.  In Algol 68, for example, a parenthesized
> > sequence of "statements" (speaking loosely) can be used as an
> > expression for its value.  Thus we might write something like
> >
> >     int average :=3D (int sum :=3D 0; for i to n do sum +:=3D f(i) od; =
sum) / n
> >
> > This capability is like the comma operator on steroids.  What can
> > appear as operands of a comma operator is comparatively limited.
> > By contrast, in "expression languages" like Algol 68 (for some
> > reason Wikipedia calls these "expression-oriented languages"),
> > the full gamut of declarations, assignment, sequencing, loops,
> > conditionals, and who knows what else, can all be part of a
> > larger expression.
> >
> > What makes this especially interesting is that I was familiar
> > with expression languages long before I ever learned C.  For me
> > the comma operator was just a stripped down version of the more
> > complete scheme adopted in expression languages.  So when I first
> > encountered C's comma operator the idea wasn't something new and
> > unfamiliar, just a simpler variation on something I already knew.
> > If someone not familiar with the concept of expression languages,
> > or something like it, first encountered the idea in the form of
> > the comma operator in C, it would naturally seem somewhat strange
> > compared to languages like Fortran or Pascal.  Very interesting
> > possibility.
> >
>=20
> One thing to consider here is if we are talking about "other people", we=
=20
> need to think about their likely knowledge and experience.  It may well=
=20
> be that Algol 68 has a "super comma" capability.  But how many C=20
> programmers have had any experience of Algol?  I have no statistics on=20
> hand, but I suspect Algol was mainly of historic interest before most=20
> current C programmers were born.  So for you, as an Algol programmer=20
> when you learned C, the comma operator came easily.  For most C=20
> programmers, who are more likely to have experience with Java, Basic, or=
=20
> perhaps C++ (if any language at all), I expect that the comma operator=20
> is something new and obscure.

its obscure for lamers, i dont know nobody for whom camma is=20
obscure=20

DB lives in another world when comm is obscure to anybody so as he said the=
y were making coding standards based on it and they probably title it 'codi=
ng standards for lamers' (point 17: 'dont use the comma as nobody knows how=
 it works')
0
fir
3/6/2016 12:27:50 PM
On Sunday, March 6, 2016 at 11:50:58 AM UTC, David Brown wrote:
> 
> One thing to consider here is if we are talking about "other people", we 
> need to think about their likely knowledge and experience.  It may well 
> be that Algol 68 has a "super comma" capability.  But how many C 
> programmers have had any experience of Algol?  I have no statistics on 
> hand, but I suspect Algol was mainly of historic interest before most 
> current C programmers were born.  So for you, as an Algol programmer 
> when you learned C, the comma operator came easily.  For most C 
> programmers, who are more likely to have experience with Java, Basic, or 
> perhaps C++ (if any language at all), I expect that the comma operator 
> is something new and obscure.
>
The whole point of a high-level computer language, or a design methodology,
is that human programmers have limitations. If that wasn't the case we'd just 
rattle off correct machine code as fast as the computer could process
our keystrokes.
But different people have different limitations. Familiarity with different
languages and paradigms is one of them. Good design involves knowing
the likely readers - are they going to be other professional embedded programmers,
or people looking for a quick way to implement something, possibly in a non-
C language but using the C code as a template? And also the trade-offs, 
what does a sophisticated construct buy that justifies using it when the 
code could be written without? Also, an intuitive understanding that difficulties
are cumulative.

If you see this

double mean(double *x, int N)
{
   double sum = 0;
   int i;

  for(i=0;i<N;i++)
    sum += x[i];
  return sum /: N;
}

you can probably guess what the odd operator means

If you see this

$f$mean : x
 Sigma x /: N x

you've got some clue, but you almost certainly can't tell me what the colon 
after the division sign means -  the unfamiliarity is too extreme.
0
Malcolm
3/6/2016 12:36:47 PM
W dniu niedziela, 6 marca 2016 13:28:10 UTC+1 u=C5=BCytkownik fir napisa=C5=
=82:
> W dniu niedziela, 6 marca 2016 12:50:58 UTC+1 u=C5=BCytkownik David Brown=
 napisa=C5=82:
> > On 05/03/16 23:44, Tim Rentsch wrote:
> > > Gareth Owen <gwowen@gmail.com> writes:
> > >
> > >> The comma operator has no equivalent (that I know of) in any other
> > >> language (besides those with explicit c compatibility).  Unlike much=
 C
> > >> syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
> > >> comma operator is a construct that no-one who is not a C expert will
> > >> readily understand.
> > >
> > > I find this comment very interesting.  In fact there are lots of
> > > languages, and indeed a whole class of languages, that have
> > > similar constructs.  In Algol 68, for example, a parenthesized
> > > sequence of "statements" (speaking loosely) can be used as an
> > > expression for its value.  Thus we might write something like
> > >
> > >     int average :=3D (int sum :=3D 0; for i to n do sum +:=3D f(i) od=
; sum) / n
> > >
> > > This capability is like the comma operator on steroids.  What can
> > > appear as operands of a comma operator is comparatively limited.
> > > By contrast, in "expression languages" like Algol 68 (for some
> > > reason Wikipedia calls these "expression-oriented languages"),
> > > the full gamut of declarations, assignment, sequencing, loops,
> > > conditionals, and who knows what else, can all be part of a
> > > larger expression.
> > >
> > > What makes this especially interesting is that I was familiar
> > > with expression languages long before I ever learned C.  For me
> > > the comma operator was just a stripped down version of the more
> > > complete scheme adopted in expression languages.  So when I first
> > > encountered C's comma operator the idea wasn't something new and
> > > unfamiliar, just a simpler variation on something I already knew.
> > > If someone not familiar with the concept of expression languages,
> > > or something like it, first encountered the idea in the form of
> > > the comma operator in C, it would naturally seem somewhat strange
> > > compared to languages like Fortran or Pascal.  Very interesting
> > > possibility.
> > >
> >=20
> > One thing to consider here is if we are talking about "other people", w=
e=20
> > need to think about their likely knowledge and experience.  It may well=
=20
> > be that Algol 68 has a "super comma" capability.  But how many C=20
> > programmers have had any experience of Algol?  I have no statistics on=
=20
> > hand, but I suspect Algol was mainly of historic interest before most=
=20
> > current C programmers were born.  So for you, as an Algol programmer=20
> > when you learned C, the comma operator came easily.  For most C=20
> > programmers, who are more likely to have experience with Java, Basic, o=
r=20
> > perhaps C++ (if any language at all), I expect that the comma operator=
=20
> > is something new and obscure.
>=20
> its obscure for lamers, i dont know nobody for whom camma is=20
> obscure=20
>=20
> DB lives in another world when comm is obscure to anybody so as he said t=
hey were making coding standards based on it and they probably title it 'co=
ding standards for lamers' (point 17: 'dont use the comma as nobody knows h=
ow it works')

ps
when i was young i disliked a word lamer
(kiedy by=C5=82em m=C5=82ody nie lubilem s=C5=82owa lamer)
(becouse nobody knows anything etc) but=20
when i become moderately experienced (as today) i began to use it becouse t=
here are
sometimes patological cases where a given lamer try to 'teach' other on the=
 things they got no lamish ideas (those fits to some here) and tis is a cas=
e im inherently allergic

so, bam, lamers

;-)
 i will goin to eat something maybe, why im so weak
0
fir
3/6/2016 12:40:35 PM
Note - read my last paragraph before replying.  It may influence what, 
if anything, you write in reply.

On 05/03/16 22:20, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
>> On 01/03/16 23:38, Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>
>> <snip>
>>
>> Although I snipped almost all of your reply, I have read it all
>> and considered it.  But I believe we are at an impasse - my
>> intention was to give some rationale for why I avoid the comma
>> operator.  You argue that my dislike is purely subjective.  I
>> don't think there is any way of convincing you otherwise.  We
>> could of course conduct surveys of programmers, programs,
>> statistics on the causes of bugs, etc., but even if that showed
>> scientifically that the comma operator was a terrible source of
>> bugs and confusion, that would be after the fact - I cannot use
>> future results to justify past opinions.
>
> I see in hindsight that the discussion went off the rails almost
> right from the start.  I have to take some of the responsibility
> for that;  if I were smarter I would have figured this out
> earlier, but oh well.  Anyway let me try to rectify those earlier
> shortcomings.
>

I think we both are responsible for the way the discussion went. 
Perhaps it is just one of these topics that is almost impossible to 
discuss sensibly in a newsgroup - or at least, that you and I were 
unable to discuss it constructively here.  I expect that if we were in 
the same room and could talk and wave our hands around, we would very 
quickly have understood each other's viewpoints.

> First off my original question was binary, and either answer
> would have been okay.  If your answer had been "oh I just don't
> like it" that would have answered my question.  Some people don't
> like eating broccoli;  there doesn't have to be a reason for
> that, they might just not like it.

This may be the key point.  I don't see the issue as binary.  I can say, 
"I don't like broccoli, because it reminds me of school dinners". 
Further, I can dig deeper and say "I don't like being reminded of school 
dinners, because the teacher in charge always shouted".  I can also say 
"lots of my old schoolfriends dislike broccoli for the same reasons. 
And some dislike it because they find it difficult to spell".  The 
dislike of broccoli is still personal and subjective - nonetheless, 
there are reasons behind it, but following down that chain of reasoning 
leads to a purely subjective basis.


As I have tried to give these "subjective reasons", and you have tried 
to fit them into your "subjective /or/ objective" pattern, we failed to 
mesh.

>
> Second, after we got past the initial binary question, I wasn't
> expecting you to justify your rationale.  I don't need to be
> convinced that your beliefs are true - I just want to know what
> those beliefs are.  This case is one of those where it is
> essential to distinguish between statements of belief and
> statements of fact.  Saying "I believe code that makes use of
> comma operators takes 50% longer to debug" is very different from
> saying "Code that makes use of comma operators takes 50% longer to
> debug".  Since the purpose (from my point of view) of entering
> into the discussion is to find out what your beliefs are, it is
> crucial that there be a distinction between which statements are
> offered only as statements of belief and which statements are
> offered as statements of fact.  More specifically, the distinction
> should be both clear in your own mind and plainly evident in the
> writing;  otherwise it's hard to know what you are saying.
>
> Third, I haven't done a good job of explaining the difference
> between the terms "subjective" and "objective" as I have been
> using them.  Basically, an assessment is subjective (or purely
> subjective, but let's ignore that refinement for the moment) if
> the only way to determine if it holds is to ask someone else
> about it.  Conversely, an assessment is objective if it can be
> determined reliably by any independent observer.  For example,
> "broccoli tastes icky" is a subjective statement, whereas a
> statement like "eating broccoli at least once a week increases
> the risk of heart attack by 40%" is an objective statement.  Note
> that a statement doesn't have to be either true or easy to verify
> to be an objective statement;  it just has to be independently
> measurable.  Similarly if you say "code that uses comma operators
> is hard to read", to me that must be a subjective statement,
> because the only way I have to decide if something is -- in your
> view -- "hard to read" is to ask you if it is;  you haven't given
> any way of measuring the property that could be performed by an
> independent observer.  The problem with a subjective statement
> is not that it's wrong, but that I don't even know what it is
> saying.  And if I don't know what it's saying, I'm right back
> at where I started - I don't know why you think what you think.
> You see the problem?

And where does "I don't like eating broccoli because it reminds me of 
school dinners" fit into this picture?

There is no way I can give objective reasons for disliking the comma 
operator, according to your definition here.  That would require some 
sort of survey or statistics, perhaps trials of some sort.  At a 
minimum, that would mean asking a sample of programmers whether /they/ 
think it is hard to read or not.  But to get real figures, we would have 
to set different groups of programmers with similar backgrounds a set of 
similar tasks, while requiring some to use comma operators and others to 
avoid it.  Clearly, that would demand more effort than is reasonable for 
a Usenet discussion!

>
>> My thoughts on what is "clear" are strongly tied to my work.
>> "Code clarity" means "do my colleagues understand the code, and
>> see it is correct?".  Are my customers happy?  How is the code
>> from my suppliers?  [...] In my world, the comma operator is
>> practically non-existent [...]
>
> Some observations (or reactions?) about this.  One, what you mean
> by "clear" is therefore not just a property of the code, but
> (also) a property of who is oberving it.

True.  My handwriting is (usually!) perfectly clear to me, but can be 
indecipherable to others.  As I see it, clarity must always be somewhat 
subjective.  The best we can do is take a selection of people, and use 
that to be "less subjective" (thus although my handwriting is clear to 
me, it can be unclear in general because many people find it hard to read).

So if I say something such as code is "clear", I would mean that I think 
that many people would find it clear to them.  I really don't see any 
other way to interpret "clarity" as a general concept.  (There are, of 
course, related objective measures such as cyclomatic complexity.  But 
those would be mentioned by name.)

>  Two, there is no way I
> would have guessed that this is what you meant.

I thought it was perfectly clear :-)

>  Three, this
> notion of what "clear" means makes it an inherently subjective
> measure - I have no way of telling whether code is "clear" without
> asking someone else (and maybe even without asking just you).

All this seems to imply that you know of some other objective definition 
of clarity.  I would be curious to know if that's the case.

>
> If at the beginning you had said "I don't like using comma
> operators because the people I'm used to working with tend not to
> use it and generally don't like it either", then that would have
> answered my question.  It gives a definite, objective reason for
> your reaction (ignoring the wishy-washiness of "tend" and
> "generally", which is not hard to work around).  It isn't easy
> necessarily to measure whether the stated condition holds, but in
> principle it could be done just by looking at the code and asking
> the other people involved.
>
>> You say I define "clarity" in terms of how I would write code?  Of
>> course I do - the concepts are intertwined.  When I write code, I
>> try to write clearly.  The concepts are not identical - code can
>> be clear even if it is written in a different way from how I would
>> have approached it.
>
> Taken as a whole this paragraph doesn't make sense.  The idea that
> you judge whether something is clear by whether it is written as
> you would write it (or expressed in a familiar way) is either true
> or false.  It can't be both true and not true.

Again, I think you are making an unreasonable and arbitrary 
categorisation.  You cannot divide everything into black or white - most 
things are shades of grey.

>
> Also I was surprised by the "Of course I do".  For me that would
> have been "Of course I don't".  Naturally if I see code written in
> a way that is similar to how I might write it then I am likely
> (but not certain!) to think the code is easily understandable, but
> the converse doesn't hold.  Looking at code where my reaction is
> "oh I would never write it this way" I still can think that the
> code is easily understandable.  To some extent I think that a mark
> of a good developer is to take in different forms (of expressing
> the same functionality) with comparative ease.

We are looking at this from different angles - I say "of course I do", 
you say "of course I don't", and yet we give almost identical reasons 
for the different conclusions.  If I were forced to give an absolute, 
black-or-white answer without nuance, then I too would say "of course I 
don't" as of course I do not defined "clarity" purely and absolutely as 
something that I would write.  But I don't believe such a black-or-white 
answer gives any useful information, and so my answer is that "how I 
would write code" is related to what I see as "clear code".

>
>> And remember that the background for this discussion was that I
>> said "I never like using the comma operator".  No matter what
>> other influences and reasoning I have for that, part of it is
>> going to be "I don't like using the comma operator because I don't
>> use the comma operator".
>
> That may be true in your case.  I don't think it has to be true in
> all cases.

I think if we dig deep enough, that is the inevitable base reason.  Thus 
the interesting thing is what we find on the way, during the digging 
process, rather than the end of the line conclusion that it is all in 
the eye of the reader.

>
>> Maybe it is even the major part - though
>> it stretches a good deal wider than just me.  Small systems
>> embedded programmers should not use the comma operator, because
>> small systems embedded programmers don't use the comma operator.
>
> If this is stated as your belief, I accept it as such.  If stated
> as a proposition that everyone should agree with, I'm afraid I
> would have to object.  However my purpose was only to discover
> your beliefs, not argue about them, so we don't have to pursue
> the second question.

I don't think my opinions on the comma operator are something that 
everyone /should/ agree on (and certainly not something that everyone 
/would/ agree with).  I /do/ think that it is going to be rare that 
using a comma operator is a useful and positive thing in code, as 
compared to alternative expressions - and thus it makes sense for people 
to think about that before using it.  But of course circumstances will 
be different for different people, and I don't think that my opinions 
here are universal.

>
>> Anyway, I think this line of discussion is closed for now.  I
>> thank you for your time, and forcing me to think a little about my
>> opinions here, but I doubt if we will get much more out of another
>> turn around the same circle.
>
> I appreciate your comments and you taking the time to write them.
> If there is something you want to say in response please go ahead,
> however in writing this I am neither expecting nor not expecting
> any response, so it's entirely up to you.
>

Discussions like this are addictive - it's hard to stop!

Perhaps we could concentrate on just a couple of points?

1. Do you really think that statements can be divided cleanly into 
"subjective" and "objective" categories, where subjective statements do 
not have any reasoning worth discussing, while objective statements have 
solid reasoning that is independent of any people involved?

2. Do you have an objective definition of clarity?

(The first point is for philosophical curiosity, but the second point 
could have a lot of practical use.)

0
David
3/6/2016 3:51:41 PM
David Brown <david.brown@hesbynett.no> writes:

> Perhaps we could concentrate on just a couple of points?
>
> 1. Do you really think that statements can be divided cleanly into
> "subjective" and "objective" categories, where subjective statements
> do not have any reasoning worth discussing, while objective statements
> have solid reasoning that is independent of any people involved?

"Objective" statements are things that I think.
"Subjective" statements are things that you think.
0
Gareth
3/6/2016 4:08:12 PM
On Saturday, March 5, 2016 at 4:44:21 PM UTC-6, Tim Rentsch wrote:
>                     In Algol 68, for example, a parenthesized
> sequence of "statements" (speaking loosely) can be used as an
> expression for its value.  Thus we might write something like
> 
>    int average := (int sum := 0; for i to n do sum +:= f(i) od; sum) / n
> 
> This capability is like the comma operator on steroids.  What can
> appear as operands of a comma operator is comparatively limited.

GCC offers that as an extension, and I would consider it in every way
superior to the comma operator.  I'm curious why nothing similar has
made it into the C Standard?  A simplistic compiler might have some
trouble allowing variables to be created while there are unnamed
compiler-temporary variables on the stack holding spilled registers,
but a compiler that can handle all the other features that have been
added to C over the years shouldn't have trouble hoisting variable
definitions over the creation of compiler temporaries.  The only other
issue I could see would be with having "goto" labels within an expression,
but that could be resolved with a rule requiring that labels within an
expression would only be reachable from within that expression.  BTW, the
issues aren't that much different with allowing declarations within a
statement.  Given something fun like:

  int crazy(int mode)
  {
    goto ONE;
   TWO:
    if (mode) goto THREE;
    int x;
    goto THREE;
   ONE:
    x=3;
    goto TWO;
   TREE:
    return x;    
  }

The ability to create variables mid-statement allows for an interesting
semantic quirk, in that having execution flow through a declaration which
does not include an initialization sets a variable to Indeterminate Value,
but neither the act of jumping from a point after an initialization to a
point before, nor vice versa, does so.  Thus, at label TWO, the name x
does not exist, but the variable which will be later named X must exist.
0
supercat
3/6/2016 5:11:22 PM
W dniu niedziela, 6 marca 2016 17:08:30 UTC+1 u=C5=BCytkownik gwowen napisa=
=C5=82:
> David Brown <david.brown@hesbynett.no> writes:
>=20
> > Perhaps we could concentrate on just a couple of points?
> >
> > 1. Do you really think that statements can be divided cleanly into
> > "subjective" and "objective" categories, where subjective statements
> > do not have any reasoning worth discussing, while objective statements
> > have solid reasoning that is independent of any people involved?
>=20
> "Objective" statements are things that I think.
> "Subjective" statements are things that you think.

comma is good becouse it allows the ommision of {} which are very burdensom=
e

for example a pice of my code where i used comma

    while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
      if(!GetMessage(&msg, NULL, 0,0)) done =3D 1;
      else
         TranslateMessage(&msg),
         DispatchMessage(&msg);

loop with if and no {} , its very fine
sad thing is only that comma "gluer " breaks on some statements that is rea=
son it is rarely used becouse this makes it less usable - this should be im=
proved

(though in general im more close to think that return a,b,c  should return =
a,b,c not c, but thats a different story about two semantically different t=
hings the later dont deny the forst, just two solutions that cant be mixed =
together


if cpma would not break one could wrote a functions loops and ifs without {=
},

sorta
void f() return a,b,c,d, if(e)  f, g, h;, i,j,k, if(l)  m,n; ,o,p,q;
(or something like that but improved)
 more pytonic style but without pythonic weirdness

=20

0
fir
3/6/2016 5:16:14 PM
On 06/03/2016 17:16, fir wrote:
> W dniu niedziela, 6 marca 2016 17:08:30 UTC+1 użytkownik gwowen napisał:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> Perhaps we could concentrate on just a couple of points?
>>>
>>> 1. Do you really think that statements can be divided cleanly into
>>> "subjective" and "objective" categories, where subjective statements
>>> do not have any reasoning worth discussing, while objective statements
>>> have solid reasoning that is independent of any people involved?
>>
>> "Objective" statements are things that I think.
>> "Subjective" statements are things that you think.
>
> comma is good becouse it allows the ommision of {} which are very burdensome
>
> for example a pice of my code where i used comma
>
>      while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
>        if(!GetMessage(&msg, NULL, 0,0)) done = 1;
>        else
>           TranslateMessage(&msg),
>           DispatchMessage(&msg);

That's great until you type ';' instead of ',' out of habit. And then 
you get some hard-to-see bugs (imagine this in thousands of lines of code).


-- 
Bartc
0
BartC
3/6/2016 5:24:42 PM
W dniu niedziela, 6 marca 2016 18:16:24 UTC+1 u=C5=BCytkownik fir napisa=C5=
=82:
>=20
> sorta
> void f() return a,b,c,d, if(e)  f, g, h;, i,j,k, if(l)  m,n; ,o,p,q;

ps this above is afaik fully today c conformant (if change a b c d
on normal statements, i was to lazy for that) one change is to allow=20

if() something; or if(){something;} to be glued as other normal particules =
and not spoil the comma-glueing fun

> (or something like that but improved)
>  more pytonic style but without pythonic weirdness

0
fir
3/6/2016 5:29:52 PM
W dniu niedziela, 6 marca 2016 18:24:53 UTC+1 u=C5=BCytkownik Bart napisa=
=C5=82:
> On 06/03/2016 17:16, fir wrote:
> > W dniu niedziela, 6 marca 2016 17:08:30 UTC+1 u=C5=BCytkownik gwowen na=
pisa=C5=82:
> >> David Brown <david.brown@hesbynett.no> writes:
> >>
> >>> Perhaps we could concentrate on just a couple of points?
> >>>
> >>> 1. Do you really think that statements can be divided cleanly into
> >>> "subjective" and "objective" categories, where subjective statements
> >>> do not have any reasoning worth discussing, while objective statement=
s
> >>> have solid reasoning that is independent of any people involved?
> >>
> >> "Objective" statements are things that I think.
> >> "Subjective" statements are things that you think.
> >
> > comma is good becouse it allows the ommision of {} which are very burde=
nsome
> >
> > for example a pice of my code where i used comma
> >
> >      while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
> >        if(!GetMessage(&msg, NULL, 0,0)) done =3D 1;
> >        else
> >           TranslateMessage(&msg),
> >           DispatchMessage(&msg);
>=20
> That's great until you type ';' instead of ',' out of habit. And then=20
> you get some hard-to-see bugs (imagine this in thousands of lines of code=
).
>=20
>=20
dont think if i would unable to learn it, really ;o
0
fir
3/6/2016 5:34:31 PM
W dniu niedziela, 6 marca 2016 18:16:24 UTC+1 u=C5=BCytkownik fir napisa=C5=
=82:
>=20
> sorta
> void f() return a,b,c,d, if(e)  f, g, h;, i,j,k, if(l)  m,n; ,o,p,q;
> (or something like that but improved)

maybe
 void f() return a,b,c,d, if(e) f, g, h; i,j,k, if(l)  m,n; o,p,q;
would also work (matter of convention which is slightly hard to chose)
it would mean that each if had to have corresponding closing ;=20
same as each loop  and each function entry

that would be conta to this while loop example where closing ;
closed both if and while now ;; would be needed but probably this is bettre=
 (better)

>  more pytonic style but without pythonic weirdness

0
fir
3/6/2016 5:49:51 PM
W dniu niedziela, 6 marca 2016 18:49:59 UTC+1 u=C5=BCytkownik fir napisa=C5=
=82:
> W dniu niedziela, 6 marca 2016 18:16:24 UTC+1 u=C5=BCytkownik fir napisa=
=C5=82:
> >=20
> > sorta
> > void f() return a,b,c,d, if(e)  f, g, h;, i,j,k, if(l)  m,n; ,o,p,q;
> > (or something like that but improved)
>=20
> maybe
>  void f() return a,b,c,d, if(e) f, g, h; i,j,k, if(l)  m,n; o,p,q;
> would also work (matter of convention which is slightly hard to chose)
> it would mean that each if had to have corresponding closing ;=20
> same as each loop  and each function entry
>=20
> that would be conta to this while loop example where closing ;
> closed both if and while now ;; would be needed but probably this is bett=
re (better)
>=20
this would conflict wit normal : usage so at least there should be
expected to  use ;; as a close for function etc, so still im not
sure as to those slight conventions that should be carefully considered and=
 tested - still if the seconds not better thr first=20
would work

0
fir
3/6/2016 5:57:24 PM
W dniu niedziela, 6 marca 2016 18:57:38 UTC+1 u=C5=BCytkownik fir napisa=C5=
=82:
> W dniu niedziela, 6 marca 2016 18:49:59 UTC+1 u=C5=BCytkownik fir napisa=
=C5=82:
> > W dniu niedziela, 6 marca 2016 18:16:24 UTC+1 u=C5=BCytkownik fir napis=
a=C5=82:
> > >=20
> > > sorta
> > > void f() return a,b,c,d, if(e)  f, g, h;, i,j,k, if(l)  m,n; ,o,p,q;
> > > (or something like that but improved)
> >=20
> > maybe
> >  void f() return a,b,c,d, if(e) f, g, h; i,j,k, if(l)  m,n; o,p,q;
> > would also work (matter of convention which is slightly hard to chose)
> > it would mean that each if had to have corresponding closing ;=20
> > same as each loop  and each function entry
> >=20
> > that would be conta to this while loop example where closing ;
> > closed both if and while now ;; would be needed but probably this is be=
ttre (better)
> >=20
> this would conflict wit normal : usage so at least there should be
> expected to  use ;; as a close for function etc, so still im not
> sure as to those slight conventions that should be carefully considered a=
nd tested - still if the seconds not better thr first=20
> would work

ps in genaral whan i thinked on that it was tempting to organise
c code in to such nested 'strips' topology: 0level-strip would be a particu=
le for a 1level-strip which on turn would be particules
for 2level etc
wuth parenthesis it is easy to do {{}{}{}}{{}{}}{{}{}}
but with only closing signs it is harder
as it probably expects more and more closing signs
a,b,c; d,e; f,g;; h,i,j; k,l;; m,n;;;=20
for c function ity is unconvenient as function shouldnt need to know on whi=
ch level to cut
this ;, convention probably also do not resolves that (it probably resolves=
 closing sign but not more levels of nesting - im not sure);
probably mixed approach closing signs and parentheses would go a bit better=
 (this seems simple math defined problem to resolve)

(where i was younger i got more energy toi just sit and resolve it but now =
im medium age old and i got no energy its scary)
0
fir
3/6/2016 6:39:04 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
[...]
> If you see this
>
> double mean(double *x, int N)
> {
>    double sum = 0;
>    int i;
>
>   for(i=0;i<N;i++)
>     sum += x[i];
>   return sum /: N;
> }
>
> you can probably guess what the odd operator means

Not really.  How does your "/:" operator differ from the "/" operator?
I might guess that it has something to do with dividing by zero, but I
have no idea what `sum /: 0` would do.

-- 
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"
0
Keith
3/6/2016 11:26:12 PM
On Sunday, March 6, 2016 at 6:28:10 AM UTC-6, fir wrote:
> W dniu niedziela, 6 marca 2016 12:50:58 UTC+1 u=C5=BCytkownik David Brown=
 napisa=C5=82:
> > On 05/03/16 23:44, Tim Rentsch wrote:
> > > Gareth Owen <gwowen@gmail.com> writes:
> > >
> > >> The comma operator has no equivalent (that I know of) in any other
> > >> language (besides those with explicit c compatibility).  Unlike much=
 C
> > >> syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
> > >> comma operator is a construct that no-one who is not a C expert will
> > >> readily understand.
> > >
> > > I find this comment very interesting.  In fact there are lots of
> > > languages, and indeed a whole class of languages, that have
> > > similar constructs.  In Algol 68, for example, a parenthesized
> > > sequence of "statements" (speaking loosely) can be used as an
> > > expression for its value.  Thus we might write something like
> > >
> > >     int average :=3D (int sum :=3D 0; for i to n do sum +:=3D f(i) od=
; sum) / n
> > >
> > > This capability is like the comma operator on steroids.  What can
> > > appear as operands of a comma operator is comparatively limited.
> > > By contrast, in "expression languages" like Algol 68 (for some
> > > reason Wikipedia calls these "expression-oriented languages"),
> > > the full gamut of declarations, assignment, sequencing, loops,
> > > conditionals, and who knows what else, can all be part of a
> > > larger expression.
> > >
> > > What makes this especially interesting is that I was familiar
> > > with expression languages long before I ever learned C.  For me
> > > the comma operator was just a stripped down version of the more
> > > complete scheme adopted in expression languages.  So when I first
> > > encountered C's comma operator the idea wasn't something new and
> > > unfamiliar, just a simpler variation on something I already knew.
> > > If someone not familiar with the concept of expression languages,
> > > or something like it, first encountered the idea in the form of
> > > the comma operator in C, it would naturally seem somewhat strange
> > > compared to languages like Fortran or Pascal.  Very interesting
> > > possibility.
> > >
> >=20
> > One thing to consider here is if we are talking about "other people", w=
e=20
> > need to think about their likely knowledge and experience.  It may well=
=20
> > be that Algol 68 has a "super comma" capability.  But how many C=20
> > programmers have had any experience of Algol?  I have no statistics on=
=20
> > hand, but I suspect Algol was mainly of historic interest before most=
=20
> > current C programmers were born.  So for you, as an Algol programmer=20
> > when you learned C, the comma operator came easily.  For most C=20
> > programmers, who are more likely to have experience with Java, Basic, o=
r=20
> > perhaps C++ (if any language at all), I expect that the comma operator=
=20
> > is something new and obscure.
>=20
> its obscure for lamers, i dont know nobody for whom camma is=20
> obscure=20
>=20
> DB lives in another world when comm is obscure to anybody so as he said t=
hey were making coding standards based on it and they probably title it 'co=
ding standards for lamers' (point 17: 'dont use the comma as nobody knows h=
ow it works')

I agree. But when asking for help with my code, I have tended to
eliminate commas so as to reduce false-positive complaints about
them. One use I still like is in a "constructor" macro where you
want to (allocate, initialize, yield pointer).

0
luser
3/7/2016 12:39:16 AM
On Sunday, March 6, 2016 at 11:16:24 AM UTC-6, fir wrote:
> comma is good becouse it allows the ommision of {} which are very burdensome

Grouping symbols are good when combining operators that are not associative;
many of the objections to the comma operator revolve around the fact that the
intended relationship between it and other operators isn't always clear.

Consider:
  int foo=bar(),boz();
  foo=bar(),boz();

If a grouping symbol were required when using a "compute X then compute Y"
operator, that would avoid such ambiguity.
0
supercat
3/7/2016 2:55:56 AM
W dniu poniedzia=C5=82ek, 7 marca 2016 03:56:05 UTC+1 u=C5=BCytkownik supe.=
...@casperkitty.com napisa=C5=82:
> On Sunday, March 6, 2016 at 11:16:24 AM UTC-6, fir wrote:
> > comma is good becouse it allows the ommision of {} which are very burde=
nsome
>=20
> Grouping symbols are good when combining operators that are not associati=
ve;
> many of the objections to the comma operator revolve around the fact that=
 the
> intended relationship between it and other operators isn't always clear.
>=20
> Consider:
>   int foo=3Dbar(),boz();
>   foo=3Dbar(),boz();
>=20
> If a grouping symbol were required when using a "compute X then compute Y=
"
> operator, that would avoid such ambiguity.


you cannot agrue something is unclear like that- becouse you also identify =
you as a=20
everlasting lamer;=20
take 5 minutes learn it and it would be clear
0
fir
3/7/2016 8:47:34 AM
On Sunday, March 6, 2016 at 11:26:19 PM UTC, Keith Thompson wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> [...]
> > If you see this
> >
> > double mean(double *x, int N)
> > {
> >    double sum = 0;
> >    int i;
> >
> >   for(i=0;i<N;i++)
> >     sum += x[i];
> >   return sum /: N;
> > }
> >
> > you can probably guess what the odd operator means
> 
> Not really.  How does your "/:" operator differ from the "/" operator?
> I might guess that it has something to do with dividing by zero, but I
> have no idea what `sum /: 0` would do.
> 
Yes, it's got to produce a defined result when dividing by zero.
It might be 0, infinity, NaN, or it might even call error code, you'd have to 
look it  up.  But pretty clearly it's a C extension that provides an operator 
that says "divide and handle the zero case properly". It's unlikely that the
author of the function has both used a new operator, and mis-written
the function.

We can deal with a bit of unfamiliarity. If you hear a new word, you can 
absorb it, usually, because the surrounding context makes it clear
what it means. But not too much. If several words in a  sentence are
unfamiliar, then you can no longer use the "fit to context" strategy.
That's also the case with programming. You have to keep the unfamiliarity 
down, the difficulties you create for your reader are cumulative.
0
Malcolm
3/7/2016 10:01:52 AM
On 07/03/2016 08:47, fir wrote:
> W dniu poniedziałek, 7 marca 2016 03:56:05 UTC+1 użytkownik supe...@casperkitty.com napisał:
>> On Sunday, March 6, 2016 at 11:16:24 AM UTC-6, fir wrote:
>>> comma is good becouse it allows the ommision of {} which are very burdensome
>>
>> Grouping symbols are good when combining operators that are not associative;
>> many of the objections to the comma operator revolve around the fact that the
>> intended relationship between it and other operators isn't always clear.
>>
>> Consider:
>>    int foo=bar(),boz();
>>    foo=bar(),boz();
>>
>> If a grouping symbol were required when using a "compute X then compute Y"
>> operator, that would avoid such ambiguity.
>
>
> you cannot agrue something is unclear like that- becouse you also identify you as a
> everlasting lamer;
> take 5 minutes learn it and it would be clear

That doesn't follow. For example, it might take seconds to learn that in 
most of Europe, they use "." to separate thousands, and "," as a decimal 
point. Instead of "," and "." as used in the UK.

So, what's this:

  5,937

Is that nearly 6, or nearly 6000? Now, context becomes more significant.

In the above example which you dismissed, suppose a version of it was 
written:

    int
    foo=bar(),boz;

split across two lines, but the 'int' part is just off the top of the 
screen so you see:

    foo=bar(),boz;

Still clear? No matter how easy it is to learn, you now can never be 
sure of the meaning of any individual line, without double-checking the 
previous line. Lots of reasons why comma operators are a bad idea.

(They wouldn't be so bad if they were always surrounded by parentheses, 
but people don't do that.)


-- 
Bartc
0
BartC
3/7/2016 10:09:50 AM
W dniu poniedzia=C5=82ek, 7 marca 2016 11:10:01 UTC+1 u=C5=BCytkownik Bart =
napisa=C5=82:
> On 07/03/2016 08:47, fir wrote:
> > W dniu poniedzia=C5=82ek, 7 marca 2016 03:56:05 UTC+1 u=C5=BCytkownik s=
upe...@casperkitty.com napisa=C5=82:
> >> On Sunday, March 6, 2016 at 11:16:24 AM UTC-6, fir wrote:
> >>> comma is good becouse it allows the ommision of {} which are very bur=
densome
> >>
> >> Grouping symbols are good when combining operators that are not associ=
ative;
> >> many of the objections to the comma operator revolve around the fact t=
hat the
> >> intended relationship between it and other operators isn't always clea=
r.
> >>
> >> Consider:
> >>    int foo=3Dbar(),boz();
> >>    foo=3Dbar(),boz();
> >>
> >> If a grouping symbol were required when using a "compute X then comput=
e Y"
> >> operator, that would avoid such ambiguity.
> >
> >
> > you cannot agrue something is unclear like that- becouse you also ident=
ify you as a
> > everlasting lamer;
> > take 5 minutes learn it and it would be clear
>=20
> That doesn't follow. For example, it might take seconds to learn that in=
=20
> most of Europe, they use "." to separate thousands, and "," as a decimal=
=20
> point. Instead of "," and "." as used in the UK.
>=20
> So, what's this:
>=20
>   5,937
>=20
> Is that nearly 6, or nearly 6000? Now, context becomes more significant.
>=20
> In the above example which you dismissed, suppose a version of it was=20
> written:
>=20
>     int
>     foo=3Dbar(),boz;
>=20
> split across two lines, but the 'int' part is just off the top of the=20
> screen so you see:
>=20
>     foo=3Dbar(),boz;
>=20
> Still clear? No matter how easy it is to learn, you now can never be=20
> sure of the meaning of any individual line, without double-checking the=
=20
> previous line. Lots of reasons why comma operators are a bad idea.
>=20
> (They wouldn't be so bad if they were always surrounded by parentheses,=
=20
> but people don't do that.)
>=20
>=20
i disagree.. not sure if i should waste more time to explain it why - try t=
o guess maybe and if no sorry you will stay uninformed

(this is becouse i think it is more your responsibility to clear your mista=
kes than main, im not a private tutor)
0
fir
3/7/2016 3:36:10 PM
W dniu poniedzia=C5=82ek, 7 marca 2016 16:36:26 UTC+1 u=C5=BCytkownik fir n=
apisa=C5=82:
> W dniu poniedzia=C5=82ek, 7 marca 2016 11:10:01 UTC+1 u=C5=BCytkownik Bar=
t napisa=C5=82:
> > On 07/03/2016 08:47, fir wrote:
> > > W dniu poniedzia=C5=82ek, 7 marca 2016 03:56:05 UTC+1 u=C5=BCytkownik=
 supe...@casperkitty.com napisa=C5=82:
> > >> On Sunday, March 6, 2016 at 11:16:24 AM UTC-6, fir wrote:
> > >>> comma is good becouse it allows the ommision of {} which are very b=
urdensome
> > >>
> > >> Grouping symbols are good when combining operators that are not asso=
ciative;
> > >> many of the objections to the comma operator revolve around the fact=
 that the
> > >> intended relationship between it and other operators isn't always cl=
ear.
> > >>
> > >> Consider:
> > >>    int foo=3Dbar(),boz();
> > >>    foo=3Dbar(),boz();
> > >>
> > >> If a grouping symbol were required when using a "compute X then comp=
ute Y"
> > >> operator, that would avoid such ambiguity.
> > >
> > >
> > > you cannot agrue something is unclear like that- becouse you also ide=
ntify you as a
> > > everlasting lamer;
> > > take 5 minutes learn it and it would be clear
> >=20
> > That doesn't follow. For example, it might take seconds to learn that i=
n=20
> > most of Europe, they use "." to separate thousands, and "," as a decima=
l=20
> > point. Instead of "," and "." as used in the UK.
> >=20
> > So, what's this:
> >=20
> >   5,937
> >=20
> > Is that nearly 6, or nearly 6000? Now, context becomes more significant=
..
> >=20
> > In the above example which you dismissed, suppose a version of it was=
=20
> > written:
> >=20
> >     int
> >     foo=3Dbar(),boz;
> >=20
> > split across two lines, but the 'int' part is just off the top of the=
=20
> > screen so you see:
> >=20
> >     foo=3Dbar(),boz;
> >=20
> > Still clear? No matter how easy it is to learn, you now can never be=20
> > sure of the meaning of any individual line, without double-checking the=
=20
> > previous line. Lots of reasons why comma operators are a bad idea.
> >=20
> > (They wouldn't be so bad if they were always surrounded by parentheses,=
=20
> > but people don't do that.)
> >=20
> >=20
> i disagree.. not sure if i should waste more time to explain it why - try=
 to guess maybe and if no sorry you will stay uninformed
>=20
> (this is becouse i think it is more your responsibility to clear your mis=
takes than main, im not a private tutor)

or maybe i will answer (dont want to live in in weird state ;) - but the an=
swer is not much interesting it just extremally simple things you seem to g=
ot a trouble to get (as i remrmber you already wrote on this)

..
..
..
..
.. (spoily)
..
..
..
..
..
..

in c there are two rules you shouldnt deny as they are c-natural and otherw=
ise 'quite right' (not bad at least, does not mean you cannot use other rul=
es in other languages but those rules are part of c 'environment')=20


1. you will not understand code meaning without context - you must read it =
anyway,
just trawel those all code lines you need to know  - youre not totally newb=
ie so you=20
just know what you need to check to make code understood (newbie could have=
 additional problem as he not necessary=20
knows the language)

2. c is 'dangerous' 'naked' language for=20
the specialist - not a language for newbbies lamers and dumb ones (I quite =
often met people who say " what if someone dunb uses=20
pointer to void, what if someone will go out array boundaries, we dislike i=
t - we are dumb and want a language for dumbs!" - I answer "well im sorry y=
oure dumb but c is not for dumbs, i  am not dumb i know what i
code and i am much happy wit c"
- this means c is language for people who understood at least most of it (a=
nd if=20
they dont understood some part they should be ready to learn it)
so dont look at the c from a point of view=20
of a lama who dont know how given line works - look at if from the point of=
 a man who absolutely clearly knows how it works

[this does not mean everything in c is=20
totally good (though c is amazing thing)
becouse even if some things are totally clear they for exammpe could look a=
 bit better or work a bit more logical, but to improve it all is not easy b=
ecouse even of some c weirdnesses has its own great=20
spirit and pseude repairing one 'side'=20
of things you can erase a couple of other=20
and with time it my show that it was wrong
(but thats digression)

If you got something on mind what those two point dont adress you may speci=
ffically explain what you mean becouse im not sure,
from what i may understood the things you=20
say are answered ad 'defeated' here - you
mostly seem to me, dont understtood that=20
c symbols need to be dependant on the context (i would probably like to do =
it more context dependant yet - as this way you can carry more information =
in lines, not less
dependant*)=20
*though the idea of making things less
contex dependant is also worth having in=20
the eye, but c as i said not conforms to=20
it right away (as example take * it means different things depending on con=
text, or you may take as an example identifier a=20
it may be int it may be float it may be=20
function it may be an array depending on the
context - and so on (In basic you could have $a is always a string !a is al=
ways an int or whatever - but c is not for the lamas, it is expected for co=
ders to follow some thought ;) (thats why it so fun and people like it so m=
uch)

0
fir
3/7/2016 4:09:49 PM
W dniu poniedzia=C5=82ek, 7 marca 2016 16:36:26 UTC+1 u=C5=BCytkownik fir n=
apisa=C5=82:
> W dniu poniedzia=C5=82ek, 7 marca 2016 11:10:01 UTC+1 u=C5=BCytkownik Bar=
t napisa=C5=82:
> > On 07/03/2016 08:47, fir wrote:
> > > W dniu poniedzia=C5=82ek, 7 marca 2016 03:56:05 UTC+1 u=C5=BCytkownik=
 supe...@casperkitty.com napisa=C5=82:
> > >> On Sunday, March 6, 2016 at 11:16:24 AM UTC-6, fir wrote:
> > >>> comma is good becouse it allows the ommision of {} which are very b=
urdensome
> > >>
> > >> Grouping symbols are good when combining operators that are not asso=
ciative;
> > >> many of the objections to the comma operator revolve around the fact=
 that the
> > >> intended relationship between it and other operators isn't always cl=
ear.
> > >>
> > >> Consider:
> > >>    int foo=3Dbar(),boz();
> > >>    foo=3Dbar(),boz();
> > >>
> > >> If a grouping symbol were required when using a "compute X then comp=
ute Y"
> > >> operator, that would avoid such ambiguity.
> > >
> > >
> > > you cannot agrue something is unclear like that- becouse you also ide=
ntify you as a
> > > everlasting lamer;
> > > take 5 minutes learn it and it would be clear
> >=20
> > That doesn't follow. For example, it might take seconds to learn that i=
n=20
> > most of Europe, they use "." to separate thousands, and "," as a decima=
l=20
> > point. Instead of "," and "." as used in the UK.
> >=20
> > So, what's this:
> >=20
> >   5,937
> >=20
> > Is that nearly 6, or nearly 6000? Now, context becomes more significant=
..
> >=20
> > In the above example which you dismissed, suppose a version of it was=
=20
> > written:
> >=20
> >     int
> >     foo=3Dbar(),boz;
> >=20
> > split across two lines, but the 'int' part is just off the top of the=
=20
> > screen so you see:
> >=20
> >     foo=3Dbar(),boz;
> >=20
> > Still clear? No matter how easy it is to learn, you now can never be=20
> > sure of the meaning of any individual line, without double-checking the=
=20
> > previous line. Lots of reasons why comma operators are a bad idea.
> >=20
> > (They wouldn't be so bad if they were always surrounded by parentheses,=
=20
> > but people don't do that.)
> >=20
> >=20
> i disagree.. not sure if i should waste more time to explain it why - try=
 to guess maybe and if no sorry you will stay uninformed
>=20
> (this is becouse i think it is more your responsibility to clear your mis=
takes than main, im not a private tutor)

or maybe i will answer (dont want to live in in weird state ;) - but the an=
swer is not much interesting it just extremally simple things you seem to g=
ot a trouble to get (as i remrmber you already wrote on this)

..
..
..
..
.. (spoily)
..
..
..
..
..
..

in c there are two rules you shouldnt deny as they are c-natural and otherw=
ise 'quite right' (not bad at least, does not mean you cannot use other rul=
es in other languages but those rules are part of c 'environment')=20


1. you will not understand code meaning without context - you must read it =
anyway,
just trawel those all code lines you need to know  - youre not totally newb=
ie so you=20
just know what you need to check to make code understood (newbie could have=
 additional problem as he not necessary=20
knows the language)

2. c is 'dangerous' 'naked' language for=20
the specialist - not a language for newbbies lamers and dumb ones (I quite =
often met people who say " what if someone dunb uses=20
pointer to void, what if someone will go out array boundaries, we dislike i=
t - we are dumb and want a language for dumbs!" - I answer "well im sorry y=
oure dumb but c is not for dumbs, i  am not dumb i know what i
code and i am much happy wit c"
- this means c is language for people who understood at least most of it (a=
nd if=20
they dont understood some part they should be ready to learn it)
so dont look at the c from a point of view=20
of a lama who dont know how given line works - look at if from the point of=
 a man who absolutely clearly knows how it works

[this does not mean everything in c is=20
totally good (though c is amazing thing)
becouse even if some things are totally clear they for exammpe could look a=
 bit better or work a bit more logical, but to improve it all is not easy b=
ecouse even of some c weirdnesses has its own great=20
spirit and pseude repairing one 'side'=20
of things you can erase a couple of other=20
and with time it my show that it was wrong
(but thats digression)

If you got something on mind what those two point dont adress you may speci=
ffically explain what you mean becouse im not sure,
from what i may understood the things you=20
say are answered ad 'defeated' here - you
mostly seem to me, dont understtood that=20
c symbols need to be dependant on the context (i would probably like to do =
it more context dependant yet - as this way you can carry more information =
in lines, not less
dependant*)=20
*though the idea of making things less
contex dependant is also worth having in=20
the eye, but c as i said not conforms to=20
it right away (as example take * it means different things depending on con=
text, or you may take as an example identifier a=20
it may be int it may be float it may be=20
function it may be an array depending on the
context - and so on (In basic you could have $a is always a string !a is al=
ways an int or whatever - but c is not for the lamas, it is expected for co=
ders to follow some thought ;) (thats why it so fun and people like it so m=
uch)

0
fir
3/7/2016 4:10:25 PM
yet one example is writing a code lines without not needed parenthesis (),
lama will argue that without parenthesis he dont know what lines mean, but =
if lama would learn it it would see that it is enough clear=20
and code is shorter=20

other point is if precedence of operators=20
is optimally chosen (some ritchie or thompson dont remember which one in so=
me interview was sayin that he regrets some choices and i also remember tha=
t some choices for and and or are weird - but this is another story - (maki=
ng comma to much breakable  may be a close kind of mistake imo)

besides that parenthesis and bracers are still avaliable becouse obviously =
not=20
ever one needs short condensed code it may
prefer longer one (but even if he prefer longer mostly this is not a reason=
 to deny the shorter)
0
fir
3/7/2016 4:34:42 PM
W dniu poniedzia=C5=82ek, 7 marca 2016 11:10:01 UTC+1 u=C5=BCytkownik Bart =
napisa=C5=82:

> In the above example which you dismissed,=20


as to this previous example=20
"
 Consider:=20
  int foo=3Dbar(),boz();=20
  foo=3Dbar(),boz();=20
"
i dont understood what it had to ilustrate,
you may explain it to me

i agree that the thing that declarations
int a,b,c;
somewhat override the comma may be confuzing for someone who not learned it=
 but if learned it still is not "unclear" ,=20

(discussable is if this is well chosen but thats very different story) (fro=
m some reasons it is not bad chosen bud for some other it probably means th=
is breaks the normal glueing comma to, like if)

0
fir
3/7/2016 5:32:12 PM
>   int foo=bar(),boz(); 

this is anyway funny line, i see a humour in it becouse this declaration is sorta useless thing, like added to spare signs and this is funny
0
fir
3/7/2016 5:45:01 PM
I could add yet a thing that to deeply understud c one should get a trawel deep intop his mind/spirit (as i should do to recover unles its to late) But network disconnect ate it (well, here repeated)
0
fir
3/7/2016 6:42:43 PM
fir <profesor.fir@gmail.com> writes:

> for example a pice of my code where i used comma
>
>     while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
>       if(!GetMessage(&msg, NULL, 0,0)) done = 1;
>       else
>          TranslateMessage(&msg),
>          DispatchMessage(&msg);
>
> loop with if and no {} , its very fine

The defence rests, your honour.
0
Gareth
3/7/2016 7:12:46 PM
On 07/03/2016 17:45, fir wrote:
>>    int foo=bar(),boz();
>
> this is anyway funny line, i see a humour in it becouse this declaration is sorta useless thing, like added to spare signs and this is funny

I wasn't even sure it was a legal declation, but apparently it is:

int boz();

is a function prototype, which is more obvious written by itself 
(usually it would be 'int boz(void);').

The amazing thing is that you can have a function prototype at all in 
the middle of a list of int declarations:

  int a, b, findindex(int* p,int n,int x), c, d;

Jeez, what a crazy language!

But apparently not even C is silly enough to have a function definition 
in the middle of such a list:

  int a, b, addint(int x,y){return x+y;}, c, d;

It draws the line there, although you have to wonder, why not allow it?

With Tiny C, the following compiles and runs (you can't declare more 
things after the function, and this must be at file scope):

int *a, b[]={10,20,30}, addint(int x,int y){return x+y;};

-- 
Bartc
0
BartC
3/7/2016 9:18:10 PM
W dniu poniedzia=C5=82ek, 7 marca 2016 22:18:22 UTC+1 u=C5=BCytkownik Bart =
napisa=C5=82:
> On 07/03/2016 17:45, fir wrote:
> >>    int foo=3Dbar(),boz();
> >
> > this is anyway funny line, i see a humour in it becouse this declaratio=
n is sorta useless thing, like added to spare signs and this is funny
>=20
> I wasn't even sure it was a legal declation, but apparently it is:
>=20
> int boz();
>=20
> is a function prototype, which is more obvious written by itself=20
> (usually it would be 'int boz(void);').
>=20
> The amazing thing is that you can have a function prototype at all in=20
> the middle of a list of int declarations:
>=20
>   int a, b, findindex(int* p,int n,int x), c, d;
>=20
for me the oryginal one line was more fun as unmaterial declaration was fun=
y glued to execution

anyway this is ilustration that if understood this is not 'unclear'

this all may be related to thing that c=20
is 'contained' in some syntax (?) rules
of compiler/c source compilation which is over that* - that make some addit=
ional layer (like a[2] is equal to 2[a] ) and such sort of things - this is
totally cracy but it also ilustration of the thing that c is multidimension=
al witty ingenious thing even in its weirdnes=20

*this layer i sadly am not able to comprehend/understood - but they are
very fine - becouse it somewhat mean=20
that you can 'cheat' a language sometimes


> Jeez, what a crazy language!
>=20
> But apparently not even C is silly enough to have a function definition=
=20
> in the middle of such a list:
>=20
>   int a, b, addint(int x,y){return x+y;}, c, d;
>=20
> It draws the line there, although you have to wonder, why not allow it?
>=20
> With Tiny C, the following compiles and runs (you can't declare more=20
> things after the function, and this must be at file scope):
>=20
> int *a, b[]=3D{10,20,30}, addint(int x,int y){return x+y;};
>=20
> --=20
> Bartc

0
fir
3/7/2016 9:40:22 PM
Ian Collins <ian-news@hotmail.com> wrote:

> Even in the world of C programming the comma operator is seldom used, at 
> least in the code I've seen.  I would go so far as to say that it is 
> sufficiently obscure to be avoided or simply forgotten by a large 
> percentage of programmers.
> 
> For the "my colleagues have difficulty with it" reason alone I consider 
> the comma operator hinders code clarity.

Meh. The same thing could be said of strxfrm(), or for that matter, of
'\v'.

Richard
0
raltbos
3/7/2016 9:42:13 PM
BartC <bc@freeuk.com> writes:
> On 07/03/2016 17:45, fir wrote:
>>>    int foo=bar(),boz();
>>
>> this is anyway funny line, i see a humour in it becouse this
>> declaration is sorta useless thing, like added to spare signs and
>> this is funny
>
> I wasn't even sure it was a legal declation, but apparently it is:
>
> int boz();
>
> is a function prototype, which is more obvious written by itself 
> (usually it would be 'int boz(void);').

No, `int boz();` is a function declaration, but it's not a prototype.
`int boz(void);` is a declaration and a prototype.  They mean different
things.  The prototype version is better.

The line

    int foo = bar(),boz();

should probably be written as:

    int foo = bar();
    int boz();

assuming that having a function declaration at block scope is a good
idea in the first place (IMHO it usually isn't).

> The amazing thing is that you can have a function prototype at all in 
> the middle of a list of int declarations:
>
>   int a, b, findindex(int* p,int n,int x), c, d;
>
> Jeez, what a crazy language!

Yes, a function prototype is a declaration, and you can have a
declaration in a list of declarations.  Which doesn't imply that
you *should*.

If you're going to hyperventilate over the fact that it's possible to
write bad but legal code in C, you've got a lot more material to work
with than this.

> But apparently not even C is silly enough to have a function definition 
> in the middle of such a list:
>
>   int a, b, addint(int x,y){return x+y;}, c, d;
>
> It draws the line there, although you have to wonder, why not allow it?

Because a function definition is not a declaration, so you can't have
one in a list of declarations.

> With Tiny C, the following compiles and runs (you can't declare more 
> things after the function, and this must be at file scope):
>
> int *a, b[]={10,20,30}, addint(int x,int y){return x+y;};

Tiny C has a bug.  (It wouldn't necessarily be non-conforming if it
printed a compile-time warning, but it doesn't, even with -Wall.)

-- 
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"
0
Keith
3/7/2016 9:47:56 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> wrote:

> On Sunday, March 6, 2016 at 11:26:19 PM UTC, Keith Thompson wrote:
> > Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> > [...]
> > > If you see this
> > >
> > > double mean(double *x, int N)
> > > {
> > >    double sum = 0;
> > >    int i;
> > >
> > >   for(i=0;i<N;i++)
> > >     sum += x[i];
> > >   return sum /: N;
> > > }
> > >
> > > you can probably guess what the odd operator means
> > 
> > Not really.  How does your "/:" operator differ from the "/" operator?
> > I might guess that it has something to do with dividing by zero, but I
> > have no idea what `sum /: 0` would do.
> > 
> Yes, it's got to produce a defined result when dividing by zero.
> It might be 0, infinity, NaN, or it might even call error code, you'd have to 
> look it  up.  But pretty clearly it's a C extension that provides an operator 
> that says "divide and handle the zero case properly".

No, it isn't. It's pretty clearly a C derivative - not necessarily a
mere extension to C itself - that provides an operator that does _some_
kind of divide. What is special about this divide, that's as clear as
New Orleans mud.
For one, I could easily believe that this is a number-crunching language
which has two kinds of each operator: one fast, and one accurate.
Whether /: would be the fast-but-less-significant-digits one, or the
perfect-rounding-but-slower one, I'd have to look up.

And that's the point. If you come across an operator you don't
understand, _you look it up_. This is as true of the comma operator as
of any truly new one. If you're a good programmer, and you come across
code you're not sure you understand, you don't panic, you don't guess,
you RTFM. Guessing is for managers. Are you a manager?

> It's unlikely that the author of the function has both used a new operator,
> and mis-written the function.

Your trust in your cow-orkers is endearing, but not necessarily
deserved.
In any case, I'd still have to look up what, for this specific function,
"mis-written" means. If the function contract specifies that it shall
not be called with N==0, or even if - since the mean of no data is
inherently meaningless - it does not specifically state that it _can_ be
called with N==0, I would never assume that it could, and therefore, I
would never assume that /: means "divide, but when the divisor is 0, do
something randomly dramatic _just_ short of nasal demons".

Richard
0
raltbos
3/7/2016 9:53:15 PM
Gareth Owen <gwowen@gmail.com> wrote:

> fir <profesor.fir@gmail.com> writes:
> 
> > for example a pice of my code where i used comma
> >
> >     while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
> >       if(!GetMessage(&msg, NULL, 0,0)) done = 1;
> >       else
> >          TranslateMessage(&msg),
> >          DispatchMessage(&msg);
> >
> > loop with if and no {} , its very fine
> 
> The defence rests, your honour.

Objection! Witness is known to be unreliable.

Richard
0
raltbos
3/7/2016 9:54:00 PM
On 06/03/16 16:08, Gareth Owen wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
>> Perhaps we could concentrate on just a couple of points?
>>
>> 1. Do you really think that statements can be divided cleanly into
>> "subjective" and "objective" categories, where subjective statements
>> do not have any reasoning worth discussing, while objective statements
>> have solid reasoning that is independent of any people involved?
>
> "Objective" statements are things that I think.
> "Subjective" statements are things that you think.

I have an independent mind. You are eccentric. He is round the twist.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/7/2016 11:45:59 PM
On Monday, March 7, 2016 at 9:53:24 PM UTC, Richard Bos wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> wrote:
> 
> > Yes, it's got to produce a defined result when dividing by zero.
> > It might be 0, infinity, NaN, or it might even call error code, 
> > you'd have to look it  up.  But pretty clearly it's a C extension 
> > that provides an operator that says "divide and handle the zero case
> > properly".
> 
> No, it isn't. It's pretty clearly a C derivative - not necessarily a
> mere extension to C itself - that provides an operator that does _some_
> kind of divide. What is special about this divide, that's as clear as
> New Orleans mud.
> For one, I could easily believe that this is a number-crunching language
> which has two kinds of each operator: one fast, and one accurate.
> Whether /: would be the fast-but-less-significant-digits one, or the
> perfect-rounding-but-slower one, I'd have to look up.
> 
> And that's the point. If you come across an operator you don't
> understand, _you look it up_. This is as true of the comma operator as
> of any truly new one. If you're a good programmer, and you come across
> code you're not sure you understand, you don't panic, you don't guess,
> you RTFM. Guessing is for managers. Are you a manager?
> 
You use strategies. You're right that it's best to be sure.
Reality is that programmers get presented with scripts written 
in languages they don't have time to learn, and which might
not even be fully documented, and they have to understand the 
programs. Which you can do, if it's not too unfamiliar, and sanely 
written.

0
Malcolm
3/7/2016 11:52:41 PM
Richard Heathfield <rjh@cpax.org.uk> writes:

> On 06/03/16 16:08, Gareth Owen wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> Perhaps we could concentrate on just a couple of points?
>>>
>>> 1. Do you really think that statements can be divided cleanly into
>>> "subjective" and "objective" categories, where subjective statements
>>> do not have any reasoning worth discussing, while objective statements
>>> have solid reasoning that is independent of any people involved?
>>
>> "Objective" statements are things that I think.
>> "Subjective" statements are things that you think.
>
> I have an independent mind. You are eccentric. He is round the twist.

"An alcoholic is someone you do not like who drinks as much as you do"
0
Gareth
3/8/2016 6:30:31 AM
W dniu poniedzia=C5=82ek, 7 marca 2016 17:10:39 UTC+1 u=C5=BCytkownik fir n=
apisa=C5=82:
>=20
> 1. you will not understand code meaning without context - you must read i=
t anyway,
> just trawel those all code lines you need=20

this is btway/anyway important thing

it 'basically' means that given symbol
or element can hawe 1147 quite different often not related meanings -it mea=
ns you can span a myriad of semantically separate solutions/elements into a=
 syntaxic surface

as i said c already has gone this way (even quite far, (depending on what t=
o talk about) c in general spans a large amount of semantic content in some=
what compressed way (though it would be hard to me wrote more on this now)


it is a way to chose if to go that way and how much, the advantage is you c=
an have complex semantics into simple looking code
- but the other side of the choice is probably also important, got to less =
exp to talk more on this







0
fir
3/12/2016 12:50:47 PM
David Brown <david.brown@hesbynett.no> writes:

> On 05/03/16 23:44, Tim Rentsch wrote:
>> Gareth Owen <gwowen@gmail.com> writes:
>>
>>> The comma operator has no equivalent (that I know of) in any other
>>> language (besides those with explicit c compatibility).  Unlike much C
>>> syntax -- for, while, do, switch (or even prefix/postfix ++) -- the
>>> comma operator is a construct that no-one who is not a C expert will
>>> readily understand.
>>
>> I find this comment very interesting.  In fact there are lots of
>> languages, and indeed a whole class of languages, that have
>> similar constructs.  In Algol 68, for example, a parenthesized
>> sequence of "statements" (speaking loosely) can be used as an
>> expression for its value.  Thus we might write something like
>>
>>     int average := (int sum := 0; for i to n do sum +:= f(i) od;  sum) / n
>>
>> This capability is like the comma operator on steroids.  What can
>> appear as operands of a comma operator is comparatively limited.
>> By contrast, in "expression languages" like Algol 68 (for some
>> reason Wikipedia calls these "expression-oriented languages"),
>> the full gamut of declarations, assignment, sequencing, loops,
>> conditionals, and who knows what else, can all be part of a
>> larger expression.
>>
>> What makes this especially interesting is that I was familiar
>> with expression languages long before I ever learned C.  For me
>> the comma operator was just a stripped down version of the more
>> complete scheme adopted in expression languages.  So when I first
>> encountered C's comma operator the idea wasn't something new and
>> unfamiliar, just a simpler variation on something I already knew.
>> If someone not familiar with the concept of expression languages,
>> or something like it, first encountered the idea in the form of
>> the comma operator in C, it would naturally seem somewhat strange
>> compared to languages like Fortran or Pascal.  Very interesting
>> possibility.
>
> One thing to consider here is if we are talking about "other people",
> we need to think about their likely knowledge and experience.  It may
> well be that Algol 68 has a "super comma" capability.  But how many C
> programmers have had any experience of Algol?  I have no statistics on
> hand, but I suspect Algol was mainly of historic interest before most
> current C programmers were born.  So for you, as an Algol programmer
> when you learned C, the comma operator came easily.  For most C
> programmers, who are more likely to have experience with Java, Basic,
> or perhaps C++ (if any language at all), I expect that the comma
> operator is something new and obscure.

Two comments.  First, I hadn't ever programmed in Algol, or AFAIR
in any other expression language (not counting Lisp, which is a
special case);  I was familiar with the general idea but had no
specific experience.  Second, just because an idea is new doesn't
mean it has to be obscure.  When I learned about expression
languages for the first time, it definitely was a new idea but
that didn't make the idea hard to understand.  The same is true
for the comma operator - it just is not that complicated.
0
Tim
3/16/2016 4:49:21 PM
Ian Collins <ian-news@hotmail.com> writes:

> On 03/06/16 11:44, Tim Rentsch wrote:
>> Gareth Owen <gwowen@gmail.com> writes:
>>
>>> David Brown <david.brown@hesbynett.no> writes:
>>>
>>>> My thoughts on what is "clear" are strongly tied to my work.  "Code
>>>> clarity" means "do my colleagues understand the code, and see it is
>>>> correct?".
>>>
>>> I think there's one objective way in which the comma operator is
>>> "unclear", and it bears on this "do my colleagues understand" question.
>>> My programming colleagues, on the whole do the bulk of their work in
>>> languages other than C, but must right code that interfaces with C.  To
>>> this end, it is sometimes necessary for them to read and comprehend C
>>> code (perhaps the documentation is lacking in some corner case.)
>>
>> "The people I work with generally have difficulty with the comma
>> operator when they see it" is (an example of) an objective
>> measure.  That could be given as a definition of, or an argument
>> for, what "unclear" is or should mean.  What I'm interested in
>> though is what the measure is, because that's where the valuable
>> information is.  Whether we call that "clarity", or "readability",
>> or "niceness", or something else, is incidental.
>
> Even in the world of C programming the comma operator is seldom used,
> at least in the code I've seen.

Here's a data point.  Doing a measurement on a sample repository
of C code, taken from a variety of sources, and comprising about
three million lines of .c files, expressions that used comma
operators occurred somewhat more often (roughly 40% more often)
than do/while loops.

> I would go so far as to say that it
> is sufficiently obscure to be avoided or simply forgotten by a large
> percentage of programmers.

I'm sure there are a lot of people who avoid it, whether they
consider it obscure or not.  I expect there are a lot of people
who don't use it because they don't think of it, but would
recognize it fairly easily if/when they see it.  Probably there
are some who don't use it and would be confused if they ran
across it looking at someone else's code;  I expect though that
this latter group correlates with not having much C experience.
Taking into account the data point above, I am skeptical that
the "large percentage" is higher than single digits of percent.

> For the "my colleagues have difficulty with it" reason alone I
> consider the comma operator hinders code clarity.

That depends on what the definition of clarity is.  If clarity
means "being readable by my colleagues with no difficulty" then
the statement is vacuously true (assuming of course that your
colleagues actually do have difficulty with it, and are not just,
say, unfamiliar).  Of course in that case "clarity" varies from
team to team.  Conversely, if clarity means "may be understood by
most C programmers without more than a few minutes of refresher
learning" then I suspect the statement is false.  If there is
no definition for clarity, then the statement is, more or less
literally, meaningless.

I find it ironic that you apparently consider comma operators too
difficult for general use, while at the same time advocating C++,
which has many more complicated and more difficult language
constructs.  Or is it your position that, say, templates, are
easier to understand than using comma operators?
0
Tim
3/16/2016 5:41:23 PM
David Brown <david.brown@hesbynett.no> writes:

> Note - read my last paragraph before replying.  It may influence what,
> if anything, you write in reply.

I am taking your advice and skipping to the end.

> Perhaps we could concentrate on just a couple of points?
>
> 1. Do you really think that statements can be divided cleanly into
> "subjective" and "objective" categories, where subjective statements
> do not have any reasoning worth discussing, while objective statements
> have solid reasoning that is independent of any people involved?

I think there has been a miscommunication, that "objective" means
"defensible" and "subjective" means "not defensible".  That isn't
what I mean.  A statement is "objective" (ie, in the sense that I
have been using it) if the truth value of the statement can be
determined by an arbitrary observer.  A statement is "subjective"
if there isn't a way for an arbitrary observer to determine its
truth value.  If I say "this painting is ugly" or "this painting
is beautiful", those are subjective statements (assuming there
isn't some unusual definition of "ugly" or "beautiful" that would
allow some sort of absolute statement).  If I say "this painting
is 200 inches tall", that is an objective statement, regardless
of how tall the painting actually is, because anyone can take out
a ruler and measure it.  Do you see what I'm getting at?

Similarly, a predicate is "subjective" or "objective" according
to whether the predicate can be applied by an arbitrary observer.

The key difference between the two cases is what meaning(s) are
possible.  An objective statement (or predicate) means the same
thing to everyone.  A subjective statement (or predicate) means
different things to different people, and often it isn't possible
to know if two people mean the same thing or not.  If I don't
know what someone means, then I can't react to it, except maybe
to say "uh huh", or "oh really?", or "hmm, that's interesting",
or "eh? say what?".  Does that make sense?

Probably it would help to give an example.  Here is sort of a
silly one:  "people who use the comma operator are 25% more
likely to develop premature baldness".  Not easy to verify, but
it is, in principle at least, an objective statement.  On the
flip side, "people who use the comma operator are 25% more
likely to be silly twits" is a subjective statement, because
there isn't an objective measure for what being a silly twit
means.  Note that this depends on definitions:  if we /define/
"silly twit" as meaning "required to wear corrective lenses when
they drive" then that earlier statement becomes an objective
one.  Possibly true, or possibly not, but objective regardless
of whether or not it's true.

> 2. Do you have an objective definition of clarity?
>
> (The first point is for philosophical curiosity, but the second
> point could have a lot of practical use.)

It's easy to give /an/ objective definition, but it may not be a
helpful one.  For example, we could define the clarity of a
sentence as "the reciprocal of the average number of syllables
per word of the sentence."  Or, probably better, we could define
the clarity of a C function definition as the average speed for
a given population of programmers to read and be able to answer
a fixed set of questions about it.  (To make this apply to more
than one function we would have to say something about how the
questions were chosen, but I think you get the idea.)  I don't
mean to say that any of these are good (or bad) definitions,
only that they are objective ones.  What I'm looking for is a
definition I can apply myself without having to ask you, or
someone else, whether the property holds or not.  So to say this
a different way, without using the word "objective", can you
tell me what you mean by clarity, so that I (or really anyone)
can judge the "clarity" of something, without having to ask
someone else?
0
Tim
3/16/2016 6:42:53 PM
On Wednesday, March 16, 2016 at 6:43:06 PM UTC, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
  If I say "this painting is ugly" or "this painting
> is beautiful", those are subjective statements (assuming there
> isn't some unusual definition of "ugly" or "beautiful" that would
> allow some sort of absolute statement).  If I say "this painting
> is 200 inches tall", that is an objective statement, regardless
> of how tall the painting actually is, because anyone can take out
> a ruler and measure it.  Do you see what I'm getting at?
>
Yes, but let's say we compare a McLean with a da Vinci or a 
Michaelangelo, and conclude that my work is superior. I think
we've got to say that the judgement is eccentric. It's not
just "taste", some painting really are works of genius, most
aren't.
0
Malcolm
3/16/2016 7:15:30 PM
On 16/03/16 19:42, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
> 
>> Note - read my last paragraph before replying.  It may influence what,
>> if anything, you write in reply.
> 
> I am taking your advice and skipping to the end.
> 
>> Perhaps we could concentrate on just a couple of points?
>>
>> 1. Do you really think that statements can be divided cleanly into
>> "subjective" and "objective" categories, where subjective statements
>> do not have any reasoning worth discussing, while objective statements
>> have solid reasoning that is independent of any people involved?
> 
> I think there has been a miscommunication, that "objective" means
> "defensible" and "subjective" means "not defensible".  That isn't
> what I mean.  A statement is "objective" (ie, in the sense that I
> have been using it) if the truth value of the statement can be
> determined by an arbitrary observer.  A statement is "subjective"
> if there isn't a way for an arbitrary observer to determine its
> truth value.  If I say "this painting is ugly" or "this painting
> is beautiful", those are subjective statements (assuming there
> isn't some unusual definition of "ugly" or "beautiful" that would
> allow some sort of absolute statement).  If I say "this painting
> is 200 inches tall", that is an objective statement, regardless
> of how tall the painting actually is, because anyone can take out
> a ruler and measure it.  Do you see what I'm getting at?
> 
> Similarly, a predicate is "subjective" or "objective" according
> to whether the predicate can be applied by an arbitrary observer.
> 
> The key difference between the two cases is what meaning(s) are
> possible.  An objective statement (or predicate) means the same
> thing to everyone.  A subjective statement (or predicate) means
> different things to different people, and often it isn't possible
> to know if two people mean the same thing or not.  If I don't
> know what someone means, then I can't react to it, except maybe
> to say "uh huh", or "oh really?", or "hmm, that's interesting",
> or "eh? say what?".  Does that make sense?
> 
> Probably it would help to give an example.  Here is sort of a
> silly one:  "people who use the comma operator are 25% more
> likely to develop premature baldness".  Not easy to verify, but
> it is, in principle at least, an objective statement.  On the
> flip side, "people who use the comma operator are 25% more
> likely to be silly twits" is a subjective statement, because
> there isn't an objective measure for what being a silly twit
> means.  Note that this depends on definitions:  if we /define/
> "silly twit" as meaning "required to wear corrective lenses when
> they drive" then that earlier statement becomes an objective
> one.  Possibly true, or possibly not, but objective regardless
> of whether or not it's true.

I agree that your definitions of "subjective" and "objective" are
reasonable - I just don't agree that this is an either/or situation.

(This is, of course, getting seriously off-topic for the group.  It is
philosophy rather than C programming.  Maybe our resident
self-proclaimed non-commonist philosopher Professor Fir will have
something to say here, if we can understand anything he writes!)

If I look outside and see a warm sunny day, and say "it's a nice day
today", is that subjective or objective?  I haven't defined "nice", but
the majority of people would understand what I meant, and agree with it
- the statement is not dependent on /me/, and therefore not 100%
subjective.  On the other hand, we cannot take out a nice-o-meter and
measure the day's niceness value.  Plus, there will be some people who
/don't/ agree that the day is nice - they wanted some rain to water the
garden, or think that a little wind is required for ideal weather.  So
the statement - or at least the /truth/ of the statement - is not 100%
objective.

Further, I would say it is impractical, close to the point of
impossibility, to be completely 100% objective.  The goal of science is
to move ever closer to true objectivity - but no scientist thinks we
have got there.  Perhaps you can make statements that are 100% objective
- but determining their truth or validity completely objectively is
impractical or impossible.

To consider "people who use the comma operator are 25% more likely to
develop premature baldness" to be a purely objective statement, we first
need purely objective definitions of terms like "people", "use", "more
likely", "premature", "baldness" - it all needs to be quantified and
defined.  And at each level, more details appear.  How bald is bald?  Is
it a fraction of the head that has lost hair?  Do you compare to hair
levels of the average person, or others in the family, or the same
person from before they started using the comma operator?  What about
thin hair?  And so on.  Then once this is all in place, you have to
count /everyone/ and categorise them as comma-users or non-comma-users,
and prematurely-bald and non-prematurely-bald.  And that includes
everyone in the past, and everyone in the future, if you want to know
the absolutely entirely 100% objective truth of the statement.

Obviously plenty of statements are subjective enough to be called
"subjective", and objective enough to be called "objective".  But I
believe that a good many of the interesting questions and statements lie
in the grey area in between.

> 
>> 2. Do you have an objective definition of clarity?
>>
>> (The first point is for philosophical curiosity, but the second
>> point could have a lot of practical use.)
> 
> It's easy to give /an/ objective definition, but it may not be a
> helpful one.  For example, we could define the clarity of a
> sentence as "the reciprocal of the average number of syllables
> per word of the sentence."  Or, probably better, we could define
> the clarity of a C function definition as the average speed for
> a given population of programmers to read and be able to answer
> a fixed set of questions about it.  (To make this apply to more
> than one function we would have to say something about how the
> questions were chosen, but I think you get the idea.)  I don't
> mean to say that any of these are good (or bad) definitions,
> only that they are objective ones.  What I'm looking for is a
> definition I can apply myself without having to ask you, or
> someone else, whether the property holds or not.  So to say this
> a different way, without using the word "objective", can you
> tell me what you mean by clarity, so that I (or really anyone)
> can judge the "clarity" of something, without having to ask
> someone else?
> 

I think we can agree that a useful, practical, intuitive and
/objective/ definition of "clarity" (or at least some aspects of
clarity) would be a useful thing, but neither of us have it.

So we will just have to live with varying degrees of subjectivity in our
"clarity".  "Clear" may mean "clear to /me/", "clear to most of my
colleagues or project team members", "clear to most people in the same
branch as me", "clear to most C programmers", "clear to most
programmers", "clear to most people".  And our judgement of what is
clear to others is also likely to be subjective (though possibly backed
up by surveys, statistics, or guides of common industry practice).
Sometimes there will also be more objective points, such as published
coding or style guides, that can give concrete definitions of aspects of
clarity (not necessarily /good/ definitions, but at least more objective
ones).

We just have to be careful to be clear about what we mean by clarity
when discussing it :-)

0
David
3/17/2016 10:03:01 AM
David Brown <david.brown@hesbynett.no> writes:

> On 16/03/16 19:42, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
[...]
>
> I think we can agree that a useful, practical, intuitive and
> /objective/ definition of "clarity" (or at least some aspects of
> clarity) would be a useful thing, but neither of us have it. [...]

This sounds to me like you are assuming that "clarity" has a
single meaning.  I don't agree with that assumption.  At
some level, that is the point I've been trying to make.
0
Tim
3/19/2016 8:34:36 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

> On Wednesday, March 16, 2016 at 6:43:06 PM UTC, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>
>   If I say "this painting is ugly" or "this painting
>
>> is beautiful", those are subjective statements (assuming there
>> isn't some unusual definition of "ugly" or "beautiful" that would
>> allow some sort of absolute statement).  If I say "this painting
>> is 200 inches tall", that is an objective statement, regardless
>> of how tall the painting actually is, because anyone can take out
>> a ruler and measure it.  Do you see what I'm getting at?
>
> Yes, but let's say we compare a McLean with a da Vinci or a 
> Michaelangelo, and conclude that my work is superior.  I think
> we've got to say that the judgement is eccentric.  It's not
> just "taste", some painting really are works of genius, most
> aren't.

But what if the other guy thinks da Vinci and Michaelangelo are
the plodders, and McLean is the genius?  I don't know anything
I can say to convince him he's wrong, or even be sure that he
is wrong.  Maybe you are just being modest.
0
Tim
3/19/2016 8:37:06 PM
On 3/19/2016 4:37 PM, Tim Rentsch wrote:
> [...]
> But what if the other guy thinks da Vinci and Michaelangelo are
> the plodders, and McLean is the genius?  I don't know anything
> I can say to convince him he's wrong, or even be sure that he
> is wrong.  Maybe you are just being modest.

     "But the fact that some geniuses were laughed at does not imply
     that all who are laughed at are geniuses. They laughed at
     Columbus, they laughed at Fulton, they laughed at the Wright
     Brothers. But they also laughed at Bozo the Clown."
     -- Carl Sagan

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
0
Eric
3/19/2016 9:20:52 PM
On 19/03/16 21:34, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
>> On 16/03/16 19:42, Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>>
> [...]
>>
>> I think we can agree that a useful, practical, intuitive and
>> /objective/ definition of "clarity" (or at least some aspects of
>> clarity) would be a useful thing, but neither of us have it. [...]
>
> This sounds to me like you are assuming that "clarity" has a
> single meaning.  I don't agree with that assumption.  At
> some level, that is the point I've been trying to make.
>

I agree with you there.


0
David
3/20/2016 1:17:11 AM
Eric Sosman <esosman@comcast-dot-net.invalid> wrote:

> On 3/19/2016 4:37 PM, Tim Rentsch wrote:
> > [...]
> > But what if the other guy thinks da Vinci and Michaelangelo are
> > the plodders, and McLean is the genius?  I don't know anything
> > I can say to convince him he's wrong, or even be sure that he
> > is wrong.  Maybe you are just being modest.
> 
>      "But the fact that some geniuses were laughed at does not imply
>      that all who are laughed at are geniuses. They laughed at
>      Columbus, they laughed at Fulton, they laughed at the Wright
>      Brothers. But they also laughed at Bozo the Clown."
>      -- Carl Sagan

I dislike that quote, mainly because Columbus was _not_ a genius. He was
a complete dumb**** who got luckier than he ever realised.

Richard
0
raltbos
3/20/2016 11:18:07 AM
In article <56ee85f0.1158171@news.xs4all.nl>,
Richard Bos <rlbos@xs4all.nl> wrote:
>Eric Sosman <esosman@comcast-dot-net.invalid> wrote:
>
>> On 3/19/2016 4:37 PM, Tim Rentsch wrote:
>> > [...]
>> > But what if the other guy thinks da Vinci and Michaelangelo are
>> > the plodders, and McLean is the genius?  I don't know anything
>> > I can say to convince him he's wrong, or even be sure that he
>> > is wrong.  Maybe you are just being modest.
>> 
>>      "But the fact that some geniuses were laughed at does not imply
>>      that all who are laughed at are geniuses. They laughed at
>>      Columbus, they laughed at Fulton, they laughed at the Wright
>>      Brothers. But they also laughed at Bozo the Clown."
>>      -- Carl Sagan
>
>I dislike that quote, mainly because Columbus was _not_ a genius. He was
>a complete dumb**** who got luckier than he ever realised.

I disagree.  Based on what I've read, he *was* a brilliant sailor and a
brilliant navigator.  Although he made some mistakes (who wouldn't have?),
he was uniquely qualified for the role that he played in history.

I know that it is PC these days to bash him, but that will pass.

-- 
"If our country is going broke, let it be from 
feeding the poor and caring for the elderly. 
And not from pampering the rich and fighting 
wars for them."

    --Living Blue in a Red State--

0
gazelle
3/20/2016 1:22:16 PM
On Sun, 20 Mar 2016 13:22:16 +0000 (UTC), gazelle@shell.xmission.com
(Kenny McCormack) wrote:

>In article <56ee85f0.1158171@news.xs4all.nl>,
>Richard Bos <rlbos@xs4all.nl> wrote:
>>Eric Sosman <esosman@comcast-dot-net.invalid> wrote:
>>
>>> On 3/19/2016 4:37 PM, Tim Rentsch wrote:
>>> > [...]
>>> > But what if the other guy thinks da Vinci and Michaelangelo are
>>> > the plodders, and McLean is the genius?  I don't know anything
>>> > I can say to convince him he's wrong, or even be sure that he
>>> > is wrong.  Maybe you are just being modest.
>>> 
>>>      "But the fact that some geniuses were laughed at does not imply
>>>      that all who are laughed at are geniuses. They laughed at
>>>      Columbus, they laughed at Fulton, they laughed at the Wright
>>>      Brothers. But they also laughed at Bozo the Clown."
>>>      -- Carl Sagan
>>
>>I dislike that quote, mainly because Columbus was _not_ a genius. He was
>>a complete dumb**** who got luckier than he ever realised.
>
>I disagree.  Based on what I've read, he *was* a brilliant sailor and a
>brilliant navigator.  Although he made some mistakes (who wouldn't have?),
>he was uniquely qualified for the role that he played in history.
>
>I know that it is PC these days to bash him, but that will pass.


Yet the entire basis of his journey east was based on a very bad
estimate of the earth's circumference - at a time when the actual
value (to some precision) was pretty well known, and not really in
question.  Had he not run into an unexpected continent and continued
east even a fairly short additional time, he and his crew would likely
have perished as their supplies would have been exhausted, since Asia
was another ~10,000 miles and six+ months further east, and they were
already near the limits of their supplies for the (longer, time wise)
trip back to Europe.
0
Robert
3/20/2016 8:34:17 PM
On 03/17/16 06:41, Tim Rentsch wrote:
> Ian Collins <ian-news@hotmail.com> writes:
>
>> On 03/06/16 11:44, Tim Rentsch wrote:
>>> Gareth Owen <gwowen@gmail.com> writes:
>>>
>>>> David Brown <david.brown@hesbynett.no> writes:
>>>>
>>>>> My thoughts on what is "clear" are strongly tied to my work.  "Code
>>>>> clarity" means "do my colleagues understand the code, and see it is
>>>>> correct?".
>>>>
>>>> I think there's one objective way in which the comma operator is
>>>> "unclear", and it bears on this "do my colleagues understand" question.
>>>> My programming colleagues, on the whole do the bulk of their work in
>>>> languages other than C, but must right code that interfaces with C.  To
>>>> this end, it is sometimes necessary for them to read and comprehend C
>>>> code (perhaps the documentation is lacking in some corner case.)
>>>
>>> "The people I work with generally have difficulty with the comma
>>> operator when they see it" is (an example of) an objective
>>> measure.  That could be given as a definition of, or an argument
>>> for, what "unclear" is or should mean.  What I'm interested in
>>> though is what the measure is, because that's where the valuable
>>> information is.  Whether we call that "clarity", or "readability",
>>> or "niceness", or something else, is incidental.
>>
>> Even in the world of C programming the comma operator is seldom used,
>> at least in the code I've seen.
>
> Here's a data point.  Doing a measurement on a sample repository
> of C code, taken from a variety of sources, and comprising about
> three million lines of .c files, expressions that used comma
> operators occurred somewhat more often (roughly 40% more often)
> than do/while loops.

How did you extract them?  Did you differentiate between comma operators 
in for loops and in general code?

>> I would go so far as to say that it
>> is sufficiently obscure to be avoided or simply forgotten by a large
>> percentage of programmers.
>
> I'm sure there are a lot of people who avoid it, whether they
> consider it obscure or not.  I expect there are a lot of people
> who don't use it because they don't think of it, but would
> recognize it fairly easily if/when they see it.  Probably there
> are some who don't use it and would be confused if they ran
> across it looking at someone else's code;  I expect though that
> this latter group correlates with not having much C experience.
> Taking into account the data point above, I am skeptical that
> the "large percentage" is higher than single digits of percent.

We'll have to agree to disagree on that one.

>> For the "my colleagues have difficulty with it" reason alone I
>> consider the comma operator hinders code clarity.
>
> That depends on what the definition of clarity is.  If clarity
> means "being readable by my colleagues with no difficulty" then
> the statement is vacuously true (assuming of course that your
> colleagues actually do have difficulty with it, and are not just,
> say, unfamiliar).  Of course in that case "clarity" varies from
> team to team.  Conversely, if clarity means "may be understood by
> most C programmers without more than a few minutes of refresher
> learning" then I suspect the statement is false.  If there is
> no definition for clarity, then the statement is, more or less
> literally, meaningless.
>
> I find it ironic that you apparently consider comma operators too
> difficult for general use, while at the same time advocating C++,
> which has many more complicated and more difficult language
> constructs.  Or is it your position that, say, templates, are
> easier to understand than using comma operators?

No, but they are more likely to be part of the programmer's "working set".

-- 
Ian Collins
0
Ian
3/21/2016 5:13:50 AM
Robert Wessel wrote:
> Kenny McCormack wrote:
> >Richard Bos wrote:
> >> ... Columbus was _not_ a genius. He was
> >>a complete dumb**** who got luckier than he ever realised.
> >
> >I disagree.  Based on what I've read, he *was* a brilliant sailor and a
> >brilliant navigator.  Although he made some mistakes (who wouldn't have?),
> >he was uniquely qualified for the role that he played in history.
> 
> Yet the entire basis of his journey east was based on a very bad
> estimate of the earth's circumference - at a time when the actual
> value (to some precision) was pretty well known, and not really in
> question.  Had he not run into an unexpected continent and continued
> east even a fairly short additional time, he and his crew would likely
> have perished as their supplies would have been exhausted, since Asia
> was another ~10,000 miles and six+ months further east, and they were
> already near the limits of their supplies for the (longer, time wise)
> trip back to Europe.

I think you mean west? (If not, then I have no idea what this means.)
0
Philip
3/21/2016 8:33:17 AM
On Mon, 21 Mar 2016 01:33:17 -0700, Philip Lantz <prl@canterey.us>
wrote:

>Robert Wessel wrote:
>> Kenny McCormack wrote:
>> >Richard Bos wrote:
>> >> ... Columbus was _not_ a genius. He was
>> >>a complete dumb**** who got luckier than he ever realised.
>> >
>> >I disagree.  Based on what I've read, he *was* a brilliant sailor and a
>> >brilliant navigator.  Although he made some mistakes (who wouldn't have?),
>> >he was uniquely qualified for the role that he played in history.
>> 
>> Yet the entire basis of his journey east was based on a very bad
>> estimate of the earth's circumference - at a time when the actual
>> value (to some precision) was pretty well known, and not really in
>> question.  Had he not run into an unexpected continent and continued
>> east even a fairly short additional time, he and his crew would likely
>> have perished as their supplies would have been exhausted, since Asia
>> was another ~10,000 miles and six+ months further east, and they were
>> already near the limits of their supplies for the (longer, time wise)
>> trip back to Europe.
>
>I think you mean west? (If not, then I have no idea what this means.)



Argh.  Of course.
0
Robert
3/21/2016 9:09:45 AM
On 21/03/16 06:13, Ian Collins wrote:
> On 03/17/16 06:41, Tim Rentsch wrote:
>>
>> I find it ironic that you apparently consider comma operators too
>> difficult for general use, while at the same time advocating C++,
>> which has many more complicated and more difficult language
>> constructs.  Or is it your position that, say, templates, are
>> easier to understand than using comma operators?
> 
> No, but they are more likely to be part of the programmer's "working set".
> 

The key differentiator here is that the comma operator is never
necessary.  Some people think it is useful or makes their code clearer
or more elegant in some way.  But AFAIK there is no code that can be
written with the comma operator that could not be re-written without it
using at most a few lines extra.

While templates are vastly more complex than the comma operator, they
are also vastly more useful.  They provide a completely new way to
structure code.  You can't replace them (not even with C11 generics and
your impressive variable-argument macros) without losing the type of
generic coding they support.



0
David
3/21/2016 9:10:54 AM
On 3/21/2016 5:10 AM, David Brown wrote:
> On 21/03/16 06:13, Ian Collins wrote:
>> On 03/17/16 06:41, Tim Rentsch wrote:
>>>
>>> I find it ironic that you apparently consider comma operators too
>>> difficult for general use, while at the same time advocating C++,
>>> which has many more complicated and more difficult language
>>> constructs.  Or is it your position that, say, templates, are
>>> easier to understand than using comma operators?
>>
>> No, but they are more likely to be part of the programmer's "working set".
>>
>
> The key differentiator here is that the comma operator is never
> necessary.  Some people think it is useful or makes their code clearer
> or more elegant in some way.  But AFAIK there is no code that can be
> written with the comma operator that could not be re-written without it
> using at most a few lines extra.

     Equally, `for' and `do' and `while' and `continue' and `break'
are never necessary: All one needs are `if' and `goto'.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
0
Eric
3/21/2016 11:55:47 AM
On 21/03/16 12:55, Eric Sosman wrote:
> On 3/21/2016 5:10 AM, David Brown wrote:
>> On 21/03/16 06:13, Ian Collins wrote:
>>> On 03/17/16 06:41, Tim Rentsch wrote:
>>>>
>>>> I find it ironic that you apparently consider comma operators too
>>>> difficult for general use, while at the same time advocating C++,
>>>> which has many more complicated and more difficult language
>>>> constructs.  Or is it your position that, say, templates, are
>>>> easier to understand than using comma operators?
>>>
>>> No, but they are more likely to be part of the programmer's "working
>>> set".
>>>
>>
>> The key differentiator here is that the comma operator is never
>> necessary.  Some people think it is useful or makes their code clearer
>> or more elegant in some way.  But AFAIK there is no code that can be
>> written with the comma operator that could not be re-written without it
>> using at most a few lines extra.
> 
>     Equally, `for' and `do' and `while' and `continue' and `break'
> are never necessary: All one needs are `if' and `goto'.
> 

Yes, that is /technically/ true - but not very helpful.  We can play
that game all the way down to a Turing machine.  The point is that the
comma operator is a minor feature in the C language, and I doubt if many
people would be seriously bothered if they were no longer allowed to use
it.  Templates in C++, on the other hand, are a major point of a great
deal of C++ code, and there are no easy replacements.  Thus although
templates are more difficult to learn and use than comma operators,
there is more to gain by learning to use them.

0
David
3/21/2016 12:23:28 PM
On 3/21/2016 8:23 AM, David Brown wrote:
> On 21/03/16 12:55, Eric Sosman wrote:
>> On 3/21/2016 5:10 AM, David Brown wrote:
>>> On 21/03/16 06:13, Ian Collins wrote:
>>>> On 03/17/16 06:41, Tim Rentsch wrote:
>>>>>
>>>>> I find it ironic that you apparently consider comma operators too
>>>>> difficult for general use, while at the same time advocating C++,
>>>>> which has many more complicated and more difficult language
>>>>> constructs.  Or is it your position that, say, templates, are
>>>>> easier to understand than using comma operators?
>>>>
>>>> No, but they are more likely to be part of the programmer's "working
>>>> set".
>>>>
>>>
>>> The key differentiator here is that the comma operator is never
>>> necessary.  Some people think it is useful or makes their code clearer
>>> or more elegant in some way.  But AFAIK there is no code that can be
>>> written with the comma operator that could not be re-written without it
>>> using at most a few lines extra.
>>
>>      Equally, `for' and `do' and `while' and `continue' and `break'
>> are never necessary: All one needs are `if' and `goto'.
>>
>
> Yes, that is /technically/ true - but not very helpful.  [...]

     Exactly.  Like your point about the comma operator.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
0
Eric
3/21/2016 12:56:19 PM
David Brown <david.brown@hesbynett.no> writes:
> On 21/03/16 06:13, Ian Collins wrote:
>> On 03/17/16 06:41, Tim Rentsch wrote:
>>>
>>> I find it ironic that you apparently consider comma operators too
>>> difficult for general use, while at the same time advocating C++,
>>> which has many more complicated and more difficult language
>>> constructs.  Or is it your position that, say, templates, are
>>> easier to understand than using comma operators?
>> 
>> No, but they are more likely to be part of the programmer's "working set".
>> 
>
> The key differentiator here is that the comma operator is never
> necessary.  Some people think it is useful or makes their code clearer
> or more elegant in some way.  But AFAIK there is no code that can be
> written with the comma operator that could not be re-written without it
> using at most a few lines extra.

No, that's not the key differentiator.  The same is true of most
features of the language.

The fact that a given feature is not entirely necessary, and can
be replaced by other features at a small cost in extra code, is
not by itself an argument that that feature is not worthwhile.
C was never intended to have an absolutely minimal feature set.

My own opinion is that good uses of the comma operator are relatively
rare, but they certainly exist.  The fact that the comma *symbol*
is used in several different ways can be confusing, but I haven't
found it to be a significant problem.  Sure, I could write code
in a C-like language that didn't have the comma operator (and,
in effect, I usually do).  But I see no reason to avoid using it
when it makes sense to do so.

The fact that the comma symbol is overloaded could be confusing, but I
personally don't find that to be much of a problem.  Unless I'm reading
code that's deliberatly obfuscated, I can easily tell the difference
between the different uses.  (The fact that parentheses are used both
for function calls and for parenthesized expressions doesn't make me
avoid parenthesized expressions.)

I suggest that you've decided that the comma operator is a bad thing,
and you're looking for arguments against it.

-- 
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"
0
Keith
3/21/2016 4:20:02 PM
Robert Wessel <robertwessel2@yahoo.com> wrote:

> On Mon, 21 Mar 2016 01:33:17 -0700, Philip Lantz <prl@canterey.us>
> wrote:
> 
> >Robert Wessel wrote:
> >> Kenny McCormack wrote:
> >> >Richard Bos wrote:
> >> >> ... Columbus was _not_ a genius. He was
> >> >>a complete dumb**** who got luckier than he ever realised.
> >> >
> >> >I disagree.  Based on what I've read, he *was* a brilliant sailor and a
> >> >brilliant navigator.  Although he made some mistakes (who wouldn't have?),
> >> >he was uniquely qualified for the role that he played in history.
> >> 
> >> Yet the entire basis of his journey east was based on a very bad
> >> estimate of the earth's circumference - at a time when the actual
> >> value (to some precision) was pretty well known, and not really in
> >> question.  Had he not run into an unexpected continent and continued
> >> east even a fairly short additional time, he and his crew would likely
> >> have perished as their supplies would have been exhausted, since Asia
> >> was another ~10,000 miles and six+ months further east, and they were
> >> already near the limits of their supplies for the (longer, time wise)
> >> trip back to Europe.
> >
> >I think you mean west? (If not, then I have no idea what this means.)
> 
> Argh.  Of course.

Well, he did intend to _end up_ in the East...

Richard
0
raltbos
3/21/2016 6:10:17 PM
On 21/03/16 17:20, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 21/03/16 06:13, Ian Collins wrote:
>>> On 03/17/16 06:41, Tim Rentsch wrote:
>>>>
>>>> I find it ironic that you apparently consider comma operators too
>>>> difficult for general use, while at the same time advocating C++,
>>>> which has many more complicated and more difficult language
>>>> constructs.  Or is it your position that, say, templates, are
>>>> easier to understand than using comma operators?
>>>
>>> No, but they are more likely to be part of the programmer's "working set".
>>>
>>
>> The key differentiator here is that the comma operator is never
>> necessary.  Some people think it is useful or makes their code clearer
>> or more elegant in some way.  But AFAIK there is no code that can be
>> written with the comma operator that could not be re-written without it
>> using at most a few lines extra.
>
> No, that's not the key differentiator.  The same is true of most
> features of the language.
>
> The fact that a given feature is not entirely necessary, and can
> be replaced by other features at a small cost in extra code, is
> not by itself an argument that that feature is not worthwhile.
> C was never intended to have an absolutely minimal feature set.
>
> My own opinion is that good uses of the comma operator are relatively
> rare, but they certainly exist.  The fact that the comma *symbol*
> is used in several different ways can be confusing, but I haven't
> found it to be a significant problem.  Sure, I could write code
> in a C-like language that didn't have the comma operator (and,
> in effect, I usually do).  But I see no reason to avoid using it
> when it makes sense to do so.
>
> The fact that the comma symbol is overloaded could be confusing, but I
> personally don't find that to be much of a problem.  Unless I'm reading
> code that's deliberatly obfuscated, I can easily tell the difference
> between the different uses.  (The fact that parentheses are used both
> for function calls and for parenthesized expressions doesn't make me
> avoid parenthesized expressions.)
>
> I suggest that you've decided that the comma operator is a bad thing,
> and you're looking for arguments against it.
>

No, I am content that /I/ rarely, if ever, use the comma operator - but 
that other people like to use it in their code.  I see it as "a bad 
thing" for my own use, but I can understand that others see it 
differently.  Despite all the posts in this thread, it is not a big deal 
as far as I am concerned.

I just thought it was a little silly to compare the comma operator in C 
with templates in C++, merely because they can both be considered 
complicated or confusing.

0
David
3/21/2016 8:18:59 PM
On Monday, March 21, 2016 at 3:19:06 PM UTC-5, David Brown wrote:
> No, I am content that /I/ rarely, if ever, use the comma operator - but 
> that other people like to use it in their code.  I see it as "a bad 
> thing" for my own use, but I can understand that others see it 
> differently.  Despite all the posts in this thread, it is not a big deal 
> as far as I am concerned.

There are some types of code for which the comma operator will rarely be
particularly useful.  There others for which it may be useful much more
often.  I can't think of many cases where the comma operator would be better
than gcc's statement-expression syntax save only for the fact that support
for the comma operator is universal, while support for gcc's extensions
isn't, but the fact that all compilers support the comma operator is a pretty
big advantage.
0
supercat
3/21/2016 8:36:21 PM
On Monday, 21 March 2016 22:36:37 UTC+2, supe...@casperkitty.com  wrote:
> On Monday, March 21, 2016 at 3:19:06 PM UTC-5, David Brown wrote:
> > No, I am content that /I/ rarely, if ever, use the comma operator - but 
> > that other people like to use it in their code.  I see it as "a bad 
> > thing" for my own use, but I can understand that others see it 
> > differently.  Despite all the posts in this thread, it is not a big deal 
> > as far as I am concerned.
> 
> There are some types of code for which the comma operator will rarely be
> particularly useful.  There others for which it may be useful much more
> often.  I can't think of many cases where the comma operator would be better
> than gcc's statement-expression syntax save only for the fact that support
> for the comma operator is universal, while support for gcc's extensions
> isn't, but the fact that all compilers support the comma operator is a pretty
> big advantage.

What are the idiomatic constructs that make comma useful?

Typically comma is added inside particular 'for', 'while' or
'do-while' loop parentheses when it is not immediately trivial to
rewrite without repeating the expression.

Where and how else? For example in 'if' or 'else if' condition or
in expressions that involve short circuit (?:, && or ||) it seemingly
only obfuscates the logic.

0
ISO
3/21/2016 9:28:25 PM
On 3/21/2016 5:28 PM, �� Tiib wrote:
>
> What are the idiomatic constructs that make comma useful?
>
> Typically comma is added inside particular 'for', 'while' or
> 'do-while' loop parentheses when it is not immediately trivial to
> rewrite without repeating the expression.
>
> Where and how else? For example in 'if' or 'else if' condition or
> in expressions that involve short circuit (?:, && or ||) it seemingly
> only obfuscates the logic.

     The only other non-contrived context where I've seen comma operators
used is in macro definitions.  It is sometimes desirable for the macro
expansion to perform multiple operations but to remain an expression
rather than a full statement; such a macro can be used in places where
a statement could not be.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
0
Eric
3/21/2016 9:49:38 PM
Eric Sosman <esosman@comcast-dot-net.invalid> wrote:

> On 3/21/2016 5:28 PM, �� Tiib wrote:
> >
> > What are the idiomatic constructs that make comma useful?
> >
> > Typically comma is added inside particular 'for', 'while' or
> > 'do-while' loop parentheses when it is not immediately trivial to
> > rewrite without repeating the expression.
> >
> > Where and how else? For example in 'if' or 'else if' condition or
> > in expressions that involve short circuit (?:, && or ||) it seemingly
> > only obfuscates the logic.
> 
>      The only other non-contrived context where I've seen comma operators
> used is in macro definitions.

The only place I've commonly used it is in statements like

  for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
    colour_cell_purple(cell, x,y);

but I really can't think of an _elegant_ way to rephrase that without
using the comma operator. (I can think of several clunky ones, of
course.)

Richard
0
raltbos
3/22/2016 11:37:56 AM
In article <56f12e05.345875@news.xs4all.nl>,
Richard Bos <rlbos@xs4all.nl> wrote:
....
>The only place I've commonly used it is in statements like
>
>  for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
>    colour_cell_purple(cell, x,y);
>
>but I really can't think of an _elegant_ way to rephrase that without
>using the comma operator. (I can think of several clunky ones, of
>course.)
>
>Richard

Well said, sir.  This whole dicussion is just a prissiness contest - to see
who, among the big strong men of CLC, can be the prissiest.

Anyway, this is how David would, presumably, re-write it:

x=0;
y=0;
while (cell[x][y]<limit) {
    colour_cell_purple(cell, x,y);
    x += dx;
    y += dy;
    }

-- 
"Every time Mitt opens his mouth, a swing state gets its wings."

(Should be on a bumper sticker)
0
gazelle
3/22/2016 11:53:57 AM
On 22/03/16 12:53, Kenny McCormack wrote:
> In article <56f12e05.345875@news.xs4all.nl>,
> Richard Bos <rlbos@xs4all.nl> wrote:
> ...
>> The only place I've commonly used it is in statements like
>>
>>  for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
>>    colour_cell_purple(cell, x,y);
>>
>> but I really can't think of an _elegant_ way to rephrase that without
>> using the comma operator. (I can think of several clunky ones, of
>> course.)
>>
>> Richard
> 
> Well said, sir.  This whole dicussion is just a prissiness contest - to see
> who, among the big strong men of CLC, can be the prissiest.
> 
> Anyway, this is how David would, presumably, re-write it:
> 
> x=0;
> y=0;
> while (cell[x][y]<limit) {
>     colour_cell_purple(cell, x,y);
>     x += dx;
>     y += dy;
>     }
> 

If we are being "prissy", then that's close - but not /quite/ how I
would write it.  Without knowing anything else about the code, I expect
I'd write:

int x = 0;
int y = 0;
while (cell[x][y] < limit) {
	colour_cell_purple(cell, x, y);
	x += dx;
	y += dy;
}

With the for-loop, my thoughts on reading it would pass through ideas like:

It's a for-loop, with x running from 0 in steps off dx up to ... Nope.
It's a for-loop, with y running from 0 in steps off dy up to ... Nope.
It's supposed to be a nested pair of for-loops with running over a grid
of x and y ... Nope.
It's a for-loop, with x and y both running in steps up to ... Nope.

It's a loop, written using "for", but with an exit condition that does
not match the variables that are incremented in the loop.  Weird.


With the while loop, my thoughts on reading it would be:

We have these local variables x and y that are initialised at 0.
We are looping until a condition is met.
Inside the loop, we are calling a function, then incrementing the local
variables.


To my mind, the while loop is clearer.  But maybe that's just /my/ mind.

(And in either case, of course, I would want to know about how the limit
and exit condition works, and how we are sure that the loop /will/ exit,
and how we are sure we are not going to overrun the array.  But that is
independent of the loop structure.)



0
David
3/22/2016 12:35:35 PM
On 22/03/2016 11:53, Kenny McCormack wrote:
> In article <56f12e05.345875@news.xs4all.nl>,
> Richard Bos <rlbos@xs4all.nl> wrote:
> ...
>> The only place I've commonly used it is in statements like
>>
>>   for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
>>     colour_cell_purple(cell, x,y);
>>
>> but I really can't think of an _elegant_ way to rephrase that without
>> using the comma operator. (I can think of several clunky ones, of
>> course.)

> Well said, sir.  This whole dicussion is just a prissiness contest - to see
> who, among the big strong men of CLC, can be the prissiest.
>
> Anyway, this is how David would, presumably, re-write it:
>
> x=0;
> y=0;
> while (cell[x][y]<limit) {
>      colour_cell_purple(cell, x,y);
>      x += dx;
>      y += dy;
>      }

I don't know about you, but this is a lot clearer! The various parts are 
neatly separated out, and it's obvious at a glance what it does.

'Parsing' the for-loop version means, for me, scanning along it looking 
for commas and counting semicolons to find the demarcations between the 
different sections.

Then follows bit of analysis to discover if this actually a normal 
for-loop or is it really a while loop. But the second version tells you 
that straight off.


-- 
Bartc
0
BartC
3/22/2016 12:40:55 PM
On 22/03/16 12:35, David Brown wrote:
> Without knowing anything else about the code, I expect
> I'd write:
>
> int x = 0;
> int y = 0;
> while (cell[x][y] < limit) {
> 	colour_cell_purple(cell, x, y);
> 	x += dx;
> 	y += dy;
> }

int x = -dx;
int y = -dy;
while(cell[x += dx][y += dy] < limit) {
      colour_cell_purple(cell, x, y);
} /* :-) */

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/22/2016 12:43:45 PM
In article <ncreat$qti$1@dont-email.me>, BartC  <bc@freeuk.com> wrote:
....
>I don't know about you, but this is a lot clearer! The various parts are 
>neatly separated out, and it's obvious at a glance what it does.

OK!  Then we're all agreed.

The 'for' statement is stupid, confusing, unnecessary, and will be removed
from the next version of the C standard.

Moved and seconded.  Meeting adjourned.

-- 
It's possible that leasing office space to a Starbucks is a greater liability
in today's GOP than is hitting your mother on the head with a hammer.
0
gazelle
3/22/2016 12:51:20 PM
On 22/03/2016 12:51, Kenny McCormack wrote:
> In article <ncreat$qti$1@dont-email.me>, BartC  <bc@freeuk.com> wrote:
> ...
>> I don't know about you, but this is a lot clearer! The various parts are
>> neatly separated out, and it's obvious at a glance what it does.
>
> OK!  Then we're all agreed.
>
> The 'for' statement is stupid, confusing, unnecessary, and will be removed
> from the next version of the C standard.

That's going too far.

For loops can stay but should only be used to express actual for loops. 
Not every possible kind of loop under the sun (except, in some code I've 
seen, actual simple A to B loops!)

-- 
Bartc
0
BartC
3/22/2016 1:32:44 PM
On Tuesday, 22 March 2016 14:35:43 UTC+2, David Brown  wrote:
> On 22/03/16 12:53, Kenny McCormack wrote:
> > In article <56f12e05.345875@news.xs4all.nl>,
> > Richard Bos <rlbos@xs4all.nl> wrote:
> > ...
> >> The only place I've commonly used it is in statements like
> >>
> >>  for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
> >>    colour_cell_purple(cell, x,y);
> >>
> >> but I really can't think of an _elegant_ way to rephrase that without
> >> using the comma operator. (I can think of several clunky ones, of
> >> course.)
> >>
> >> Richard
> > 
> > Well said, sir.  This whole dicussion is just a prissiness contest - to see
> > who, among the big strong men of CLC, can be the prissiest.
> > 
> > Anyway, this is how David would, presumably, re-write it:
> > 
> > x=0;
> > y=0;
> > while (cell[x][y]<limit) {
> >     colour_cell_purple(cell, x,y);
> >     x += dx;
> >     y += dy;
> >     }
> > 
> 
> If we are being "prissy", then that's close - but not /quite/ how I
> would write it.  Without knowing anything else about the code, I expect
> I'd write:
> 
> int x = 0;
> int y = 0;
> while (cell[x][y] < limit) {
> 	colour_cell_purple(cell, x, y);
> 	x += dx;
> 	y += dy;
> }

Good. When it is already 'while' then it may be slightly harder. 
Things like parameters are reduced to simplify it down to essence:

    Result process_command_sequence(void)
    {
        Command *cmd;
        while (cmd_read(&cmd), cmd_has_follow_ups(cmd))
        {
            Result res = cmd_process_interim(cmd);
            if (res != Result_Proceed)
                return res; 
        }
        return cmd_process_final(cmd);
    }

0
ISO
3/22/2016 2:01:52 PM
BartC <bc@freeuk.com> wrote:

> On 22/03/2016 12:51, Kenny McCormack wrote:
> > In article <ncreat$qti$1@dont-email.me>, BartC  <bc@freeuk.com> wrote:
> > ...
> >> I don't know about you, but this is a lot clearer! The various parts are
> >> neatly separated out, and it's obvious at a glance what it does.
> >
> > OK!  Then we're all agreed.
> >
> > The 'for' statement is stupid, confusing, unnecessary, and will be removed
> > from the next version of the C standard.
> 
> That's going too far.
> 
> For loops can stay but should only be used to express actual for loops. 
> Not every possible kind of loop under the sun (except, in some code I've 
> seen, actual simple A to B loops!)

I've said it before, Bart, and I'll say it again: if you want BASIC, you
know where to find it.

Richard
0
raltbos
3/22/2016 3:49:45 PM
On Tuesday, March 22, 2016 at 12:35:43 PM UTC, David Brown wrote:
> 
> I'd write:
> 
> int x = 0;
> int y = 0;
> while (cell[x][y] < limit) {
> 	colour_cell_purple(cell, x, y);
> 	x += dx;
> 	y += dy;
> }
> 
My contribution

 int x = 0;
 int y = 0;
 while (cell[x][y] < limit) {
        assert(x < cells_width);
        assert(y < cells_height);
 	colour_cell_purple(cell, x, y);
 	x += dx;
 	y += dy;
 }

Those asserts are highly likely to fire until quite a late stage
of development, given that code.
0
Malcolm
3/22/2016 7:16:40 PM
On 22/03/2016 15:49, Richard Bos wrote:
> BartC <bc@freeuk.com> wrote:
>
>> On 22/03/2016 12:51, Kenny McCormack wrote:
>>> In article <ncreat$qti$1@dont-email.me>, BartC  <bc@freeuk.com> wrote:
>>> ...
>>>> I don't know about you, but this is a lot clearer! The various parts are
>>>> neatly separated out, and it's obvious at a glance what it does.
>>>
>>> OK!  Then we're all agreed.
>>>
>>> The 'for' statement is stupid, confusing, unnecessary, and will be removed
>>> from the next version of the C standard.
>>
>> That's going too far.
>>
>> For loops can stay but should only be used to express actual for loops.
>> Not every possible kind of loop under the sun (except, in some code I've
>> seen, actual simple A to B loops!)
>
> I've said it before, Bart, and I'll say it again: if you want BASIC, you
> know where to find it.

OK, you think conflating half a dozen varieties of loop into one 
language statement, including wacko custom loops people can invent, and 
allowing all sorts of extra junk to be crammed in for good measure, is 
good language design and good coding practice.

Your opinion. Mine's a little different.

(Algol68 also combines several kinds of loop into one statement, but it 
does it properly in that you aren't even aware the various loops are 
related.)


-- 
Bartc

0
BartC
3/22/2016 7:20:58 PM
On 22/03/16 19:20, BartC wrote:

<snip>

> OK, you think conflating half a dozen varieties of loop into one
> language statement, including wacko custom loops people can invent, and
> allowing all sorts of extra junk to be crammed in for good measure, is
> good language design and good coding practice.
>
> Your opinion. Mine's a little different.

OK, you think removing all the power and flexibility of C's for loop, 
and turning it into the brain-dead version that BASIC uses, is good 
language design and good coding practice.

Your opinion. Mine's a little different.

Of course, we /could/ express our opinions in a measured and reasonable 
way, as if we were pretending to be grown-ups. Would that really be too 
much to ask?

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/22/2016 9:30:38 PM
On 22/03/2016 21:30, Richard Heathfield wrote:
> On 22/03/16 19:20, BartC wrote:
>
> <snip>
>
>> OK, you think conflating half a dozen varieties of loop into one
>> language statement, including wacko custom loops people can invent, and
>> allowing all sorts of extra junk to be crammed in for good measure, is
>> good language design and good coding practice.
>>
>> Your opinion. Mine's a little different.
>
> OK, you think removing all the power and flexibility of C's for loop,
> and turning it into the brain-dead version that BASIC uses, is good
> language design and good coding practice.

Actually, yes. If brain-dead means you can see at a glance what 
something does, then that's good.

> Your opinion. Mine's a little different.

I don't need to put forward an argument at all. Just compare:

  for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
      colour_cell_purple(cell, x,y);

with:

  x=0;
  y=0;
  while (cell[x][y]<limit) {
      colour_cell_purple(cell, x,y);
      x += dx;
      y += dy;
  }

and make up your own mind. You might also notice that one of those (I'm 
not saying which) is already in a form, other than minor details of 
syntax, compatible with the same statement in a hundred other languages, 
not just the ones derived from C.

(Except, perhaps, early BASIC.)

-- 
Bartc
0
BartC
3/22/2016 9:52:24 PM
On Tuesday March 22 2016 17:52, in comp.lang.c, "BartC" <bc@freeuk.com> wrote:

> On 22/03/2016 21:30, Richard Heathfield wrote:
>> On 22/03/16 19:20, BartC wrote:
>>
>> <snip>
>>
>>> OK, you think conflating half a dozen varieties of loop into one
>>> language statement, including wacko custom loops people can invent, and
>>> allowing all sorts of extra junk to be crammed in for good measure, is
>>> good language design and good coding practice.
>>>
>>> Your opinion. Mine's a little different.
>>
>> OK, you think removing all the power and flexibility of C's for loop,
>> and turning it into the brain-dead version that BASIC uses, is good
>> language design and good coding practice.
> 
> Actually, yes. If brain-dead means you can see at a glance what
> something does, then that's good.

Then you should like
  MOVE ZERO TO X
  MOVE ZERO TO Y
  PERFORM UNTIL CELL[X][Y] IS GREATER THAN OR EQUAL TO LIMIT
    CALL 'COLOUR-CELL-PURPLE' USING CELL, X, Y
    ADD DX TO X GIVING X
    ADD DY TO Y GIVING Y
  END-PERFORM

(Just my two cents  ;-)  )

-- 
Lew Pitcher
"In Skills, We Trust"
PGP public key available upon request

0
Lew
3/22/2016 10:02:32 PM
On 22/03/16 21:52, BartC wrote:
> On 22/03/2016 21:30, Richard Heathfield wrote:
>> On 22/03/16 19:20, BartC wrote:
>>
>> <snip>
>>
>>> OK, you think conflating half a dozen varieties of loop into one
>>> language statement, including wacko custom loops people can invent, and
>>> allowing all sorts of extra junk to be crammed in for good measure, is
>>> good language design and good coding practice.
>>>
>>> Your opinion. Mine's a little different.
>>
>> OK, you think removing all the power and flexibility of C's for loop,
>> and turning it into the brain-dead version that BASIC uses, is good
>> language design and good coding practice.
>
> Actually, yes. If brain-dead means you can see at a glance what
> something does, then that's good.

No, in normal speech "brain-dead" is generally used to mean "without 
intelligence".

>> Your opinion. Mine's a little different.
>
> I don't need to put forward an argument at all.

Of course not. And neither do I.


> Just compare:
>
>   for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
>       colour_cell_purple(cell, x,y);

I'd add braces and spaces, but apart from that it looks all right to me.

> with:
>
>   x=0;
>   y=0;
>   while (cell[x][y]<limit) {
>       colour_cell_purple(cell, x,y);
>       x += dx;
>       y += dy;
>   }

That looks all right too. I prefer the first one, though.

> and make up your own mind.

I'll keep the for-loop version then, if that's all right with you. It's 
clean and tidy. The while-loop is okay, too, but it's a bit sprawlier 
than it needs to be.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/22/2016 10:07:32 PM
On 22/03/2016 22:07, Richard Heathfield wrote:
> On 22/03/16 21:52, BartC wrote:
>> On 22/03/2016 21:30, Richard Heathfield wrote:

>>> OK, you think removing all the power and flexibility of C's for loop,
>>> and turning it into the brain-dead version that BASIC uses, is good
>>> language design and good coding practice.
>>
>> Actually, yes. If brain-dead means you can see at a glance what
>> something does, then that's good.
>
> No, in normal speech "brain-dead" is generally used to mean "without
> intelligence".

That's interesting. If I write this in Basic:

  for i=1 to 10
  print i, sqr(i)
  next j

then the language rightly complains. But if I write in C:

   for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));

the compiler doesn't so much as raise an eyebrow. Apparently there's 
nothing wrong with this code!

Which one did you say was brain-dead again? As C's for-statement is just 
an empty shell.

(Although that was wasn't my complaint, which was misusing it for things 
other than straightforward A to B or 0..N-1 loops.)

-- 
Bartc

0
BartC
3/22/2016 10:28:04 PM
On 22/03/16 22:28, BartC wrote:
> On 22/03/2016 22:07, Richard Heathfield wrote:
>> On 22/03/16 21:52, BartC wrote:
>>> On 22/03/2016 21:30, Richard Heathfield wrote:
>
>>>> OK, you think removing all the power and flexibility of C's for loop,
>>>> and turning it into the brain-dead version that BASIC uses, is good
>>>> language design and good coding practice.
>>>
>>> Actually, yes. If brain-dead means you can see at a glance what
>>> something does, then that's good.
>>
>> No, in normal speech "brain-dead" is generally used to mean "without
>> intelligence".
>
> That's interesting. If I write this in Basic:
>
>   for i=1 to 10
>   print i, sqr(i)
>   next j
>
> then the language rightly complains.

Indeed, because that's not the way for-loops work in BASIC.

> But if I write in C:
>
>    for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));
>
> the compiler doesn't so much as raise an eyebrow.

Why should it? That's legal C.

> Apparently there's nothing wrong with this code!

How do you draw that conclusion? Do you really believe that a program is 
correct if it doesn't produce a diagnostic message? If that were the 
case, it would be very easy to write an office suite. You could just 
write: int main(void) { return 0; } and expect the compiler to guess 
what you meant to happen. C doesn't work like that. C expects you to 
know what you're doing. If you don't know what you're doing, C might not 
be the best language for you.

>
> Which one did you say was brain-dead again?

The BASIC for-loop is very constrained in how it can be used. The C 
for-loop is much more flexible and powerful.

> As C's for-statement is just
> an empty shell.

It's a tool. It's a powerful tool, and one that you have to use 
carefully, but you can achieve a lot with it.

> (Although that was wasn't my complaint, which was misusing it for things
> other than straightforward A to B or 0..N-1 loops.)

"Using it in a way that BartC doesn't like" and "misusing it" are not 
synonymous, much as you might prefer to think otherwise.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/22/2016 10:47:55 PM
BartC <bc@freeuk.com> writes:
[...]
> I don't need to put forward an argument at all. Just compare:
>
>  for (x=0, y=0; cell[x][y]<limit; x+=dx, y+=dy)
>      colour_cell_purple(cell, x,y);
>
> with:
>
>  x=0;
>  y=0;
>  while (cell[x][y]<limit) {
>      colour_cell_purple(cell, x,y);
>      x += dx;
>      y += dy;
>  }
>
> and make up your own mind.

Fair enough.

Personally, I'd use curly braces on the first one, and I'd use a
C99-style initializer in the for loop header.  I'd also use a little
more whitespace.

    for (int x=0, y=0; cell[x][y] < limit; x += dx, y += dy) {
        colour_cell_purple(cell, x, y);
    }

But even without those changes, I find it clearer than the version using
a while loop.

Why?  Because I know how C for loops work, and I don't expect them to be
used only for simple iteration over a range of integer values.

>                            You might also notice that one of those
> (I'm not saying which) is already in a form, other than minor details
> of syntax, compatible with the same statement in a hundred other
> languages, not just the ones derived from C.

I write C code with the intent that it should be understandable by
readers who are familiar with 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"
0
Keith
3/22/2016 10:48:26 PM
On 22/03/2016 22:47, Richard Heathfield wrote:
> On 22/03/16 22:28, BartC wrote:

>> But if I write in C:
>>
>>    for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));
>>
>> the compiler doesn't so much as raise an eyebrow.
>
> Why should it? That's legal C.

That's exactly the problem. Sometimes constraints are good. Any human 
looking at that carefully (as he will do after the code doesn't work) 
will spot the problem. The compiler can't.

>> Apparently there's nothing wrong with this code!
>
> How do you draw that conclusion? Do you really believe that a program is
> correct if it doesn't produce a diagnostic message? If that were the
> case, it would be very easy to write an office suite. You could just
> write: int main(void) { return 0; } and expect the compiler to guess
> what you meant to happen. C doesn't work like that. C expects you to
> know what you're doing. If you don't know what you're doing, C might not
> be the best language for you.

You're right, it isn't. Not for manually writing in anyway.

(These days I write: 'for i:=1 to 10 do...' and a translator produces: 
'for (i=1; i<=10; ++i) ...'. It knows that, even though I only wrote 'i' 
once, the C version requires three identical copies. But strangely, the 
C compiler itself doesn't know that!)

>> Which one did you say was brain-dead again?
>
> The BASIC for-loop is very constrained in how it can be used. The C
> for-loop is much more flexible and powerful.

Like 'if' and 'goto' then, but the problems of missing using those are 
more obvious.


>> As C's for-statement is just
>> an empty shell.
>
> It's a tool. It's a powerful tool, and one that you have to use
> carefully, but you can achieve a lot with it.

It wouldn't be so bad if they had two for statements: one simple one 
that I prefer, and another for people to write more convoluted loops.

>> (Although that was wasn't my complaint, which was misusing it for things
>> other than straightforward A to B or 0..N-1 loops.)
>
> "Using it in a way that BartC doesn't like" and "misusing it" are not
> synonymous, much as you might prefer to think otherwise.

Think about where the 'for' keyword may have originated from. Given what 
it mostly seems to be used as, they might have done better to have 
called it 'while', and discarded what is now the while statement:

while (i=0; i<n; ++i) ....

When you really do want a basic while, just write 'while (;cond;)' or 
the compiler might allow both semicolons to be dropped.

-- 
Bartc


0
BartC
3/22/2016 11:05:28 PM
BartC <bc@freeuk.com> writes:
> On 22/03/2016 22:47, Richard Heathfield wrote:
>> On 22/03/16 22:28, BartC wrote:
>>> But if I write in C:
>>>
>>>    for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));
>>>
>>> the compiler doesn't so much as raise an eyebrow.
>>
>> Why should it? That's legal C.
>
> That's exactly the problem. Sometimes constraints are good. Any human 
> looking at that carefully (as he will do after the code doesn't work) 
> will spot the problem. The compiler can't.

Do you have the same complaint about this?

    if (i >= 1 && j <= 10)

C's for loop is more flexible than, say, the version you find in BASIC.
You can do more things with it -- some of which may be incorrect.

In comparison to a hypothetical version of the for loop like, perhaps,

    for (i, 1, 100)

C's for loop is only slightly more verbose, substantially more flexible,
and perhaps a bit more error-prone.  I think that's a good tradeoff.

[...]

> Think about where the 'for' keyword may have originated from. Given what 
> it mostly seems to be used as, they might have done better to have 
> called it 'while', and discarded what is now the while statement:
>
> while (i=0; i<n; ++i) ....
>
> When you really do want a basic while, just write 'while (;cond;)' or 
> the compiler might allow both semicolons to be dropped.

Sounds like it might be a great idea for some language other than C.

But seriously, would calling the keyword "while" rather than "for"
really alleviate your concern?  Is your complaint that trivial?

-- 
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"
0
Keith
3/22/2016 11:43:54 PM
On 22/03/16 23:05, BartC wrote:
> On 22/03/2016 22:47, Richard Heathfield wrote:
>> On 22/03/16 22:28, BartC wrote:
>
>>> But if I write in C:
>>>
>>>    for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));
>>>
>>> the compiler doesn't so much as raise an eyebrow.
>>
>> Why should it? That's legal C.
>
> That's exactly the problem.

I don't see it.

> Sometimes constraints are good.

And sometimes they're bad. This is one of those times when they're bad.

> Any human
> looking at that carefully (as he will do after the code doesn't work)
> will spot the problem. The compiler can't.

I spotted it immediately without having to look carefully, and I didn't 
have to try the code out, either. When you program in C, or indeed in 
any language, you take responsibility for getting the program right. The 
compiler can help you a little, but there is no substitute for knowing 
the language and knowing how to use it effectively. People who can't do 
that, for /any/ language, have (at least) three choices: they can stop 
using the language; they can improve their knowledge; or they can stop 
learning, carry on using the language, and blame the language whenever 
they make a mistake. The first option is a sensible choice. So is the 
second. The third, however, is not.

>>> Apparently there's nothing wrong with this code!
>>
>> How do you draw that conclusion? Do you really believe that a program is
>> correct if it doesn't produce a diagnostic message? If that were the
>> case, it would be very easy to write an office suite. You could just
>> write: int main(void) { return 0; } and expect the compiler to guess
>> what you meant to happen. C doesn't work like that. C expects you to
>> know what you're doing. If you don't know what you're doing, C might not
>> be the best language for you.
>
> You're right, it isn't. Not for manually writing in anyway.

Then don't use it. Not for manually writing in anyway. And, magically, 
the problem goes away.

> (These days I write: 'for i:=1 to 10 do...' and a translator produces:
> 'for (i=1; i<=10; ++i) ...'. It knows that, even though I only wrote 'i'
> once, the C version requires three identical copies. But strangely, the
> C compiler itself doesn't know that!)

The C for-loop is flexible and powerful. One cost of that flexibility 
and power is that the programmer has to know what he's dealing with. The 
compiler doesn't complain when you do for(i = this; j < that; k += 
theother) because /that might be what you meant/, and it's legal C. I 
think it was Doug Gwyn who said that the only way for a language to stop 
people doing stupid things was to stop them doing clever things. C 
allows you to do clever things, and the cost is that it can't always 
stop you doing stupid things. So the onus is on the programmer not to do 
stupid things.

>>> Which one did you say was brain-dead again?
>>
>> The BASIC for-loop is very constrained in how it can be used. The C
>> for-loop is much more flexible and powerful.
>
> Like 'if' and 'goto' then, but the problems of missing using those are
> more obvious.

The C 'if' is certainly more powerful than the original Dartford BASIC 
'if'. What kind of misuse did you have in mind? As for 'goto', well, I 
can't bring myself to care about that because I never use it.

>>> As C's for-statement is just
>>> an empty shell.
>>
>> It's a tool. It's a powerful tool, and one that you have to use
>> carefully, but you can achieve a lot with it.
>
> It wouldn't be so bad if they had two for statements: one simple one
> that I prefer, and another for people to write more convoluted loops.

But you already have that. If you want for(i = 0; i < n; i++) it isn't 
difficult to type, I assure you.

<speculation snipped>

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/23/2016 12:07:12 AM
On 22/03/2016 23:43, Keith Thompson wrote:
> BartC <bc@freeuk.com> writes:

>> Think about where the 'for' keyword may have originated from. Given what
>> it mostly seems to be used as, they might have done better to have
>> called it 'while', and discarded what is now the while statement:
>>
>> while (i=0; i<n; ++i) ....
>>
>> When you really do want a basic while, just write 'while (;cond;)' or
>> the compiler might allow both semicolons to be dropped.
>
> Sounds like it might be a great idea for some language other than C.

No, it's specially a good idea for C.

> But seriously, would calling the keyword "while" rather than "for"
> really alleviate your concern?  Is your complaint that trivial?

It would certainly make it clearer that C's 'for' isn't a for-statement 
as normally understood in other languages (where you specify start and 
end points, or a sequence to iterate over, and the language looks after 
the intermediate steps).

It's an embellished while-loop, which can be used to crudely emulate a 
for-statement.

-- 
Bartc
0
BartC
3/23/2016 12:33:11 AM
On 3/22/2016 8:33 PM, BartC wrote:
> On 22/03/2016 23:43, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
> 
>>> Think about where the 'for' keyword may have originated from. Given what
>>> it mostly seems to be used as, they might have done better to have
>>> called it 'while', and discarded what is now the while statement:
>>>
>>> while (i=0; i<n; ++i) ....
>>>
>>> When you really do want a basic while, just write 'while (;cond;)' or
>>> the compiler might allow both semicolons to be dropped.
>>
>> Sounds like it might be a great idea for some language other than C.
> 
> No, it's specially a good idea for C.
> 
>> But seriously, would calling the keyword "while" rather than "for"
>> really alleviate your concern?  Is your complaint that trivial?
> 
> It would certainly make it clearer that C's 'for' isn't a for-statement
> as normally understood in other languages (where you specify start and
> end points, or a sequence to iterate over, and the language looks after
> the intermediate steps).
> 
> It's an embellished while-loop, which can be used to crudely emulate a
> for-statement.
> 

When you get right down to it, ANY for loop is an embellished while loop.


-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
0
Jerry
3/23/2016 12:44:58 AM
On 23/03/2016 00:44, Jerry Stuckle wrote:
> On 3/22/2016 8:33 PM, BartC wrote:

>> It would certainly make it clearer that C's 'for' isn't a for-statement
>> as normally understood in other languages (where you specify start and
>> end points, or a sequence to iterate over, and the language looks after
>> the intermediate steps).
>>
>> It's an embellished while-loop, which can be used to crudely emulate a
>> for-statement.
>>
>
> When you get right down to it, ANY for loop is an embellished while loop.

Behind the scenes perhaps, where you can't see the joins. So you write:

  for x in A {S}

in some languages, and that's it. You don't need to write:

  temp = 0;
  while (temp<sizeof(A)/sizeof(A[0]) {
    x = A[temp];
    S;
    ++temp;
  }

or, still trying to pretend this is a for-loop rather than a 
rearrangement of a while-loop:

  for (temp=0; temp<sizeof(A)/sizeof(A[0]); ++temp) {
    x=A[temp];
    S;
  }

(Compare how much you have to write compared to the original, and how 
much you can now get wrong. And I actually did get it wrong, but noticed 
just in time!)

But maybe C should be commended for being so transparent. And, of 
course, flexible.

-- 
Bartc

0
BartC
3/23/2016 1:10:56 AM
BartC <bc@freeuk.com> writes:
> On 22/03/2016 23:43, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>>> Think about where the 'for' keyword may have originated from. Given what
>>> it mostly seems to be used as, they might have done better to have
>>> called it 'while', and discarded what is now the while statement:
>>>
>>> while (i=0; i<n; ++i) ....
>>>
>>> When you really do want a basic while, just write 'while (;cond;)' or
>>> the compiler might allow both semicolons to be dropped.
>>
>> Sounds like it might be a great idea for some language other than C.
>
> No, it's specially a good idea for C.

A change that would break nearly every existing C program does not
strike me as a good idea.

>> But seriously, would calling the keyword "while" rather than "for"
>> really alleviate your concern?  Is your complaint that trivial?
>
> It would certainly make it clearer that C's 'for' isn't a for-statement 
> as normally understood in other languages (where you specify start and 
> end points, or a sequence to iterate over, and the language looks after 
> the intermediate steps).

It *is* a for loop.  It's just not a for loop in the sense used in some
other languages.  What makes BASIC's version right and C's wrong?

BTW, a number of other languages have adopted C-style for loops,
including of course C++ and Objective-C, but also Perl, the Bash shell,
and PHP.

C' for loop is more general and expressive than a while loop (though of
course any for loop can be translated to an equivalent while loop).  It
encapsulates initialization, a continuation condition, and iteration
into one neat package.  It lets you do the equivalent of a BASIC-style
FOR loop using an idiom that's recognized by any C programmer.

> It's an embellished while-loop, which can be used to crudely emulate a 
> for-statement.

I see nothing crude about it.

If large numbers of C programmers have no problem with C-style for
loops, but you do, perhaps it's not C that has the problem.

-- 
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"
0
Keith
3/23/2016 1:13:08 AM
On 23/03/16 00:33, BartC wrote:
> On 22/03/2016 23:43, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> Think about where the 'for' keyword may have originated from. Given what
>>> it mostly seems to be used as, they might have done better to have
>>> called it 'while', and discarded what is now the while statement:
>>>
>>> while (i=0; i<n; ++i) ....
>>>
>>> When you really do want a basic while, just write 'while (;cond;)' or
>>> the compiler might allow both semicolons to be dropped.
>>
>> Sounds like it might be a great idea for some language other than C.
>
> No, it's specially a good idea for C.

You don't use C (except as a target language), so why would you care? 
Those who actually /do/ use C seem to be quite happy with the way it 
does for-loops.

<snip>

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/23/2016 1:15:37 AM
BartC <bc@freeuk.com> writes:

> On 23/03/2016 00:44, Jerry Stuckle wrote:
<snip>
>> When you get right down to it, ANY for loop is an embellished while loop.
>
> Behind the scenes perhaps, where you can't see the joins. So you write:
>
>  for x in A {S}
>
> in some languages, and that's it. You don't need to write:
>
>  temp = 0;
>  while (temp<sizeof(A)/sizeof(A[0]) {
>    x = A[temp];
>    S;
>    ++temp;
>  }

Sure, and in some languages the correspondence is purely theoretical
making the for loop much more than an embellished while.  In AWK, for
example, iterating though an associative array (for (i in A) ...) does
not correspond to any while loop you'd ever be able to use.

<snip>
-- 
Ben.
0
Ben
3/23/2016 1:23:44 AM
In article <87r3f2kmvz.fsf@bsb.me.uk>,
Ben Bacarisse  <ben.usenet@bsb.me.uk> wrote:
....
>Sure, and in some languages the correspondence is purely theoretical
>making the for loop much more than an embellished while.  In AWK, for
>example, iterating though an associative array (for (i in A) ...) does
>not correspond to any while loop you'd ever be able to use.

(I'm not sure what point you are/were trying to make by bringing this up,
but since you mentioned my favorite programming language, I feel I must
comment...)

Actually, AWK's 'for' loop corresponds to:

idx = getfirstindex();	/* Assume this returns NULL on error (eof) */
while (idx != NULL) {
    /* do stuff with idx and the associated array element */
    idx = getnextindex();	/* Assume this returns NULL on error (eof) */
    }

-- 
Religion is what keeps the poor from murdering the rich.

	- Napoleon Bonaparte -

0
gazelle
3/23/2016 5:30:14 AM
W dniu =C5=9Broda, 23 marca 2016 00:44:06 UTC+1 u=C5=BCytkownik Keith Thomp=
son napisa=C5=82:
> BartC <bc@freeuk.com> writes:
> > On 22/03/2016 22:47, Richard Heathfield wrote:
> >> On 22/03/16 22:28, BartC wrote:
> >>> But if I write in C:
> >>>
> >>>    for (i=3D1; j<=3D10; ++k) printf ("%d %f\n",i,sqrt(i));
> >>>
> >>> the compiler doesn't so much as raise an eyebrow.
> >>
> >> Why should it? That's legal C.
> >
> > That's exactly the problem. Sometimes constraints are good. Any human=
=20
> > looking at that carefully (as he will do after the code doesn't work)=
=20
> > will spot the problem. The compiler can't.
>=20
> Do you have the same complaint about this?
>=20
>     if (i >=3D 1 && j <=3D 10)
>=20
> C's for loop is more flexible than, say, the version you find in BASIC.
> You can do more things with it -- some of which may be incorrect.
>=20
> In comparison to a hypothetical version of the for loop like, perhaps,
>=20
>     for (i, 1, 100)
>=20

range operator could be incorporated in c=20
(with keyword to or operator like : (used in pascal or where as i remember)=
  or better .. for example)

int i =3D 1 to 999

im not 100% sure as it should, but it=20
would be obviouslu usefull in some cases

if(!(x,y in 0..639, 0..479) ) //*

combined with or and and keywords for logical and or or instead of && ||



* i often write releted code and in present c it looks convoluted

inline int PixelIsOutFrame(int x, int y)
{
  extern int frame_size_x ;
  extern int frame_size_y ;

  if( (x<0) || (y<0) || (x>frame_size_x-1) || (y>frame_size_y-1) )
   return 1;
  else
   return 0;
}

the ranges could be also used in=20
more wide set of cases (yawn)
=20


> C's for loop is only slightly more verbose, substantially more flexible,
> and perhaps a bit more error-prone.  I think that's a good tradeoff.
>=20
> [...]
>=20
> > Think about where the 'for' keyword may have originated from. Given wha=
t=20
> > it mostly seems to be used as, they might have done better to have=20
> > called it 'while', and discarded what is now the while statement:
> >
> > while (i=3D0; i<n; ++i) ....
> >
> > When you really do want a basic while, just write 'while (;cond;)' or=
=20
> > the compiler might allow both semicolons to be dropped.
>=20
> Sounds like it might be a great idea for some language other than C.
>=20
> But seriously, would calling the keyword "while" rather than "for"
> really alleviate your concern?  Is your complaint that trivial?
>=20
> --=20
> Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~ks=
t>
> 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"
0
fir
3/23/2016 8:32:40 AM
On 22/03/16 23:28, BartC wrote:
> On 22/03/2016 22:07, Richard Heathfield wrote:
>> On 22/03/16 21:52, BartC wrote:
>>> On 22/03/2016 21:30, Richard Heathfield wrote:
> 
>>>> OK, you think removing all the power and flexibility of C's for loop,
>>>> and turning it into the brain-dead version that BASIC uses, is good
>>>> language design and good coding practice.
>>>
>>> Actually, yes. If brain-dead means you can see at a glance what
>>> something does, then that's good.
>>
>> No, in normal speech "brain-dead" is generally used to mean "without
>> intelligence".
> 
> That's interesting. If I write this in Basic:
> 
>  for i=1 to 10
>  print i, sqr(i)
>  next j
> 
> then the language rightly complains. But if I write in C:
> 
>   for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));
> 
> the compiler doesn't so much as raise an eyebrow. Apparently there's
> nothing wrong with this code!

"With freedom comes responsibility - that's why we fear it".

The best you can do is find coding rules, development procedures, and
tools that fit the type of flexibility you feel appropriate when
programming.  If (like me) you prefer your for loops to be more limited,
akin to those in many other languages, then the first step is to have
coding rules and a coding style that disallows complicated for loops -
you are very unlikely to write a loop like the one above by accident.
Then you can have development procedures such as code reviews to help
spot mistakes.  And you use tools such as gcc's warnings or a linter as
an aid.  There is a good chance that a loop like the one above is going
to be spotted by gcc's warnings about unused or uninitialised variables
(especially if you define your local variables in small scopes rather
than all at the start of the function).

> 
> Which one did you say was brain-dead again? As C's for-statement is just
> an empty shell.
> 
> (Although that was wasn't my complaint, which was misusing it for things
> other than straightforward A to B or 0..N-1 loops.)
> 



0
David
3/23/2016 10:41:21 AM
On 23/03/2016 01:13, Keith Thompson wrote:
> BartC <bc@freeuk.com> writes:

>> It would certainly make it clearer that C's 'for' isn't a for-statement
>> as normally understood in other languages (where you specify start and
>> end points, or a sequence to iterate over, and the language looks after
>> the intermediate steps).
>
> It *is* a for loop.  It's just not a for loop in the sense used in some
> other languages.  What makes BASIC's version right and C's wrong?

The problem is that C's version has become so wide-spread that people 
are going to associate 'for' with that form.

But going back a bit, one defining characteristic of what I call 
'proper' for statements is that there is an official loop variable, 
which is also automatically compared with a limit and automatically 
stepped to the next value.

Examples are Fortran (called 'do'), the Algols, PL/I, Cobol, Basic, 
Pascal, Ada, Lua, Python, Ruby, even Bash (Bash also has C's version).

But in C, there is no official loop variable. There is no official 
anything. No automatic compare. No automatic compare operator. No 
automatic increment.

for(A;B;C) is just a keyword and 3 statements/expressions. They can be 
anything. A sort of DIY kit of possibly an interative for, or possibly 
anything else.

That's why I don't think highly of it.

-- 
Bartc
0
BartC
3/23/2016 2:33:08 PM
On 23/03/16 14:33, BartC wrote:
> On 23/03/2016 01:13, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> It would certainly make it clearer that C's 'for' isn't a for-statement
>>> as normally understood in other languages (where you specify start and
>>> end points, or a sequence to iterate over, and the language looks after
>>> the intermediate steps).
>>
>> It *is* a for loop.  It's just not a for loop in the sense used in some
>> other languages.  What makes BASIC's version right and C's wrong?
>
> The problem is that C's version has become so wide-spread that people
> are going to associate 'for' with that form.

Firstly, that's not a problem, because C's for-loop is better. Secondly, 
your objection seems to be that C's for-loop is used in so many 
languages that people now associate 'for' with C's for-loop, and that 
directly contradicts your claim that C's 'for' isn't a for-statement as 
normally understood in other languages.

> But going back a bit, one defining characteristic of what I call
> 'proper' for statements is that there is an official loop variable,
> which is also automatically compared with a limit and automatically
> stepped to the next value.

What you call 'proper' for statements is entirely up to you, but you 
haven't yet explained /why/ your view is so compelling as to require 
everyone to change to it. All you've really said is that you prefer 
BASIC's for to C's for. Fine, that's your prerogative, and nobody is 
going to try to change your mind. (Well, some people will, but you don't 
have to listen.)

But if you're proposing a fundamental change to C, you're going to have 
to be a lot more convincing, because a change to for-loop syntax will 
break just about every C program in existence.

And if you're not proposing a fundamental change to C, aren't you really 
just bitching? And whilst it can be fun to bitch for a little while, 
don't you think you're overdoing it?

<snip>

> for(A;B;C) is just a keyword and 3 statements/expressions. They can be
> anything. A sort of DIY kit of possibly an interative for, or possibly
> anything else.
>
> That's why I don't think highly of it.

And it's why I /do/ think highly of it.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/23/2016 3:02:32 PM
On Tuesday, March 22, 2016 at 7:45:10 PM UTC-5, Jerry Stuckle wrote:
> When you get right down to it, ANY for loop is an embellished while loop.

Not necessarily.  Some compilers may seek to optimize "for" and "while"
loops in different ways, especially if the authors believe that compilers
should subscribe to the Principle of Least Astonishment whether or not the
Standard requires it [a principle I would like to see return to the
culture].  Given that the vast majority of programs in many fields are
subject to a requirement that they must refrain from doing certain things
no matter what input they receive, there could be considerable benefit to
allowing programmers to give substantial freedom to compilers without giving
them total freedom.

For example, I would suggest that the vast majority of useful optimizations
that can be achieved by making integer overflow yield Undefined Behavior
could be achieved by having it yield Partially-Indeterminate results(*), but
there one additional freedom could enable some more useful optimizations:
allow a for-loop condition to arbitrarily be evaluated as false in cases
where an upcoming loop iteration would otherwise cause overflow.  Such a
behavior could not be described in terms of any causal execution model, but
would be harmless in many real-world applications.  Loops which would need
to run precisely as indicated even in the presence of overflow could be
written as "while" loops.

(*) Each evaluation of a 32-bit rvalue holding a Partially-Indeterminate
    Value may independently yield a value that behaves as any mathematical
    integer which is congruent to the stored value, mod 4294967296.  Other
    integer sizes would do likewise.  On a system with a 16-bit int type,
    after "int x=32767; x++;", x would hold a Partially-Indeterminate Value
    which is congruent to -32768 (mod 65536).  The statement "int32_t y=x;"
    would cause y to hold a Partially-Indeterminate Value which is congruent
    to to some fixed value (mod 4294967296), and that fixed value would be
    congruent to -32768 (mod 65536) but otherwise Unspecified.
0
supercat
3/23/2016 3:18:23 PM
On Wednesday, March 23, 2016 at 10:41:33 AM UTC, David Brown wrote:
> On 22/03/16 23:28, BartC wrote:
> 
> > then the language rightly complains. But if I write in C:
> > 
> >   for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));
> > 
> > the compiler doesn't so much as raise an eyebrow. Apparently there's
> > nothing wrong with this code!
> 
> "With freedom comes responsibility - that's why we fear it".
> 
> The best you can do is find coding rules, development procedures, and
> tools that fit the type of flexibility you feel appropriate when
> programming.  If (like me) you prefer your for loops to be more limited,
> akin to those in many other languages, then the first step is to have
> coding rules and a coding style that disallows complicated for loops -
> you are very unlikely to write a loop like the one above by accident.
> Then you can have development procedures such as code reviews to help
> spot mistakes.  And you use tools such as gcc's warnings or a linter as
> an aid.  There is a good chance that a loop like the one above is going
> to be spotted by gcc's warnings about unused or uninitialised variables
> (especially if you define your local variables in small scopes rather
> than all at the start of the function).
> 
Bart's example is obviously nonsensical, the language allows it, and that's
a flaw or a weak point. However no-one is actually likely to write a loop
like that deliberately. What does often happen is that you get something like

for(i=0;i<M;i++)
{
   for(j=0;i<N;j++)
   {
       array[i][j] = x;
   }
}

A j looks similar to an i except for the little curve at the bottom (the poet John Donne
preached a sermon against the letter j). It's easy to miss the error.

Th other thing that sometimes happens is that people use a combination of
for flexibility,  comma operators, and logical operator short-circuiting to build
quite complex flow control logic into a single for statement. The result can be very 
hard to decipher.
0
Malcolm
3/23/2016 5:16:52 PM
On Wed, 23 Mar 2016 14:33:08 +0000, BartC <bc@freeuk.com> wrote:

>On 23/03/2016 01:13, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> It would certainly make it clearer that C's 'for' isn't a for-statement
>>> as normally understood in other languages (where you specify start and
>>> end points, or a sequence to iterate over, and the language looks after
>>> the intermediate steps).
>>
>> It *is* a for loop.  It's just not a for loop in the sense used in some
>> other languages.  What makes BASIC's version right and C's wrong?
>
>The problem is that C's version has become so wide-spread that people 
>are going to associate 'for' with that form.
>
Why should this matter? If you're programming in C your programming in
C. If you're crossing language constructs and forms in your head it's
time to fix your concepts or abandon a language to avoid confusion. 


>But going back a bit, one defining characteristic of what I call 
>'proper' for statements is that there is an official loop variable, 
>which is also automatically compared with a limit and automatically 
>stepped to the next value.
>
>Examples are Fortran (called 'do'), the Algols, PL/I, Cobol, Basic, 
>Pascal, Ada, Lua, Python, Ruby, even Bash (Bash also has C's version).
>
>But in C, there is no official loop variable. There is no official 
>anything. No automatic compare. No automatic compare operator. No 
>automatic increment.
>
If you want that, write perl, not C:

#!/usr/local/bin/perl
 
@list = (2, 20, 30, 40, 50);

foreach $a (@list){
    print "value of a: $a\n";
}

>for(A;B;C) is just a keyword and 3 statements/expressions. They can be 
>anything. A sort of DIY kit of possibly an interative for, or possibly 
>anything else.
>
>That's why I don't think highly of it.

It would be nice if C had 'foreach' as I have often encountered places
where I would have used it in C but C's 'for' keyword certainly offers
flexibility over rigidity and that is actually a strength worth
mastering.
0
Geoff
3/23/2016 6:43:06 PM
On Wednesday, March 23, 2016 at 1:17:16 PM UTC-4, Malcolm McLean wrote:
> On Wednesday, March 23, 2016 at 10:41:33 AM UTC, David Brown wrote:
> > On 22/03/16 23:28, BartC wrote:
> > 
> > > then the language rightly complains. But if I write in C:
> > > 
> > >   for (i=1; j<=10; ++k) printf ("%d %f\n",i,sqrt(i));
> > > 
> > > the compiler doesn't so much as raise an eyebrow. Apparently there's
> > > nothing wrong with this code!
> > 
> > "With freedom comes responsibility - that's why we fear it".
> > 
> > The best you can do is find coding rules, development procedures, and
> > tools that fit the type of flexibility you feel appropriate when
> > programming.  If (like me) you prefer your for loops to be more limited,
> > akin to those in many other languages, then the first step is to have
> > coding rules and a coding style that disallows complicated for loops -
> > you are very unlikely to write a loop like the one above by accident.
> > Then you can have development procedures such as code reviews to help
> > spot mistakes.  And you use tools such as gcc's warnings or a linter as
> > an aid.  There is a good chance that a loop like the one above is going
> > to be spotted by gcc's warnings about unused or uninitialised variables
> > (especially if you define your local variables in small scopes rather
> > than all at the start of the function).
> > 
> Bart's example is obviously nonsensical, the language allows it, and that's
> a flaw or a weak point. However no-one is actually likely to write a loop
> like that deliberately. What does often happen is that you get something like
> 
> for(i=0;i<M;i++)
> {
>    for(j=0;i<N;j++)
>    {
>        array[i][j] = x;
>    }
> }
> 
> A j looks similar to an i except for the little curve at the bottom (the poet John Donne
> preached a sermon against the letter j). It's easy to miss the error.
> 
> Th other thing that sometimes happens is that people use a combination of
> for flexibility,  comma operators, and logical operator short-circuiting to build
> quite complex flow control logic into a single for statement. The result can be very 
> hard to decipher.

I mostly avoid commas in for loops since introducing them seems to turn an
otherwise innocuous looking 'for' statement into a terse definition of a
state machine.  Some people are adept at mentally processing those, others
less so.  I find myself more in the second category, so I tend to avoid
writing more complicated for loops using those constructs.

In the few instances where I came across a loop of that kind, I do remember
that I found it especially painful when there is a problem (usually a
boundary condition of some kind) and I want to trace through a complicated
for loop with print statements or in a debugger.

Best regards,
John D.
0
jadill33
3/23/2016 6:55:32 PM
On 23/03/2016 15:02, Richard Heathfield wrote:
> On 23/03/16 14:33, BartC wrote:
>> On 23/03/2016 01:13, Keith Thompson wrote:
>>> BartC <bc@freeuk.com> writes:
>>
>>>> It would certainly make it clearer that C's 'for' isn't a for-statement
>>>> as normally understood in other languages (where you specify start and
>>>> end points, or a sequence to iterate over, and the language looks after
>>>> the intermediate steps).
>>>
>>> It *is* a for loop.  It's just not a for loop in the sense used in some
>>> other languages.  What makes BASIC's version right and C's wrong?
>>
>> The problem is that C's version has become so wide-spread that people
>> are going to associate 'for' with that form.
>
> Firstly, that's not a problem, because C's for-loop is better.

It seems I may have to use an actual argument here.

Probably at least 99% of the loops I use fall into a handful of patterns 
(endless loop, repeat N times, iterate from A to B, while, repeat 
(do-while), and iterate over values in a list).

In the syntax I normally use, with its dedicated loop statements, in 
nearly every case I need to impart less information to make it work, 
then the C equivalent.

This means more opportunity for error in C (in ways the language can't 
detect), plus more typing and less readability.

Other people's coding patterns may be different, but it's hard to 
believe that the vast majority of loops in C don't fall into one of the 
same common set of patterns.

You seem to be saying the cost of C's for statement is worth it for the 
flexibility and power, even if that power is rarely needed.

(In the syntax I use, I have a set of very easy dedicated loop 
constructs. But I also have a loop that works like C's for, as I found 
out yesterday because I've never used it! The point though is that you 
can have both a complex loop statement, and a simple one.)


-- 
Bartc
0
BartC
3/23/2016 7:09:20 PM
W dniu =C5=9Broda, 23 marca 2016 09:33:02 UTC+1 u=C5=BCytkownik fir napisa=
=C5=82:
> W dniu =C5=9Broda, 23 marca 2016 00:44:06 UTC+1 u=C5=BCytkownik Keith Tho=
mpson napisa=C5=82:
> > BartC <bc@freeuk.com> writes:
> > > On 22/03/2016 22:47, Richard Heathfield wrote:
> > >> On 22/03/16 22:28, BartC wrote:
> > >>> But if I write in C:
> > >>>
> > >>>    for (i=3D1; j<=3D10; ++k) printf ("%d %f\n",i,sqrt(i));
> > >>>
> > >>> the compiler doesn't so much as raise an eyebrow.
> > >>
> > >> Why should it? That's legal C.
> > >
> > > That's exactly the problem. Sometimes constraints are good. Any human=
=20
> > > looking at that carefully (as he will do after the code doesn't work)=
=20
> > > will spot the problem. The compiler can't.
> >=20
> > Do you have the same complaint about this?
> >=20
> >     if (i >=3D 1 && j <=3D 10)
> >=20
> > C's for loop is more flexible than, say, the version you find in BASIC.
> > You can do more things with it -- some of which may be incorrect.
> >=20
> > In comparison to a hypothetical version of the for loop like, perhaps,
> >=20
> >     for (i, 1, 100)
> >=20
>=20
> range operator could be incorporated in c=20
> (with keyword to or operator like : (used in pascal or where as i remembe=
r)  or better .. for example)
>=20
> int i =3D 1 to 999
>=20
> im not 100% sure as it should, but it=20
> would be obviouslu usefull in some cases
>=20
> if(!(x,y in 0..639, 0..479) ) //*
>=20
> combined with or and and keywords for logical and or or instead of && ||
>=20
>=20
>=20
> * i often write releted code and in present c it looks convoluted
>=20
> inline int PixelIsOutFrame(int x, int y)
> {
>   extern int frame_size_x ;
>   extern int frame_size_y ;
>=20
>   if( (x<0) || (y<0) || (x>frame_size_x-1) || (y>frame_size_y-1) )
>    return 1;
>   else
>    return 0;
> }
>=20
> the ranges could be also used in=20
> more wide set of cases (yawn)
>
this is anyway wider topic as it seem stat such range would have to born wh=
ole algebra, there is also small doubt if this is ok with the spirit of c o=
r it is not, will say maybe more on this other time
0
fir
3/23/2016 7:53:31 PM
On 23/03/2016 19:09, BartC wrote:

> it's hard to
> believe that the vast majority of loops in C don't fall into one of the
> same common set of patterns.

I've put some 2300 for-statements here (from 380Kloc of CPython and 
Sqlite sources):

http://pastebin.com/mA6A10h4

On lines 1 to 200, and 1500 to 1550, I've marked with an asterisk those 
loops that look like simple iterations, or endless loops.

Most of the rest could probably be ordinary while loops, but for some 
reason people like to obfuscate their code by using for loops for everthing.

(I've done the same extraction on my own code, and it's so much easier 
on the eye. If it says it's a for-statement, then you're 100% certain 
it's simple iteration over two values.)

-- 
Bartc
0
BartC
3/23/2016 9:18:30 PM
BartC <bc@freeuk.com> writes:
> On 23/03/2016 19:09, BartC wrote:
>> it's hard to
>> believe that the vast majority of loops in C don't fall into one of the
>> same common set of patterns.
>
> I've put some 2300 for-statements here (from 380Kloc of CPython and 
> Sqlite sources):
>
> http://pastebin.com/mA6A10h4
>
> On lines 1 to 200, and 1500 to 1550, I've marked with an asterisk those 
> loops that look like simple iterations, or endless loops.
>
> Most of the rest could probably be ordinary while loops, but for some 
> reason people like to obfuscate their code by using for loops for everthing.
>
> (I've done the same extraction on my own code, and it's so much easier 
> on the eye. If it says it's a for-statement, then you're 100% certain 
> it's simple iteration over two values.)

It's easier on *your* eyes, not on mine.

If I see

    for(i=0; i<view->ndim; i++) {

I'm equally certain that it's a simple iteration over a range of values
(even though I'd add a few spaces).

*I* don't find for loops obfuscated, nor do most C programmers.  I'm
sorry you do, but obviously there's nothing I can do about that.

Are you willing to accept that most C programmers don't have the same
problem with for loops that you do, and that for us your proposal to
<loaded_word>cripple</loaded_word> C-style for loops would be a bad
thing?  And that no such change will ever happen, because it would break
existing code?

I completely agree with you that *you* don't like C-style for loops.

Is there anything left to discuss on this particular topic?

-- 
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"
0
Keith
3/23/2016 9:54:47 PM
On 23/03/16 19:09, BartC wrote:
> On 23/03/2016 15:02, Richard Heathfield wrote:
>> On 23/03/16 14:33, BartC wrote:
<snip>
>>> The problem is that C's version has become so wide-spread that people
>>> are going to associate 'for' with that form.
>>
>> Firstly, that's not a problem, because C's for-loop is better.
>
> It seems I may have to use an actual argument here.

Not a bad idea. You should try it more often. :-)

> Probably at least 99% of the loops I use fall into a handful of patterns
> (endless loop, repeat N times, iterate from A to B, while, repeat
> (do-while), and iterate over values in a list).
>
> In the syntax I normally use, with its dedicated loop statements, in
> nearly every case I need to impart less information to make it work,
> then the C equivalent.

Okay. So your argument is that you only use for-loops in the way you are 
used to, and when you use it only in those ways, you need to tell C more 
than you need to tell some other languages. If you were the only user of 
C in the whole world, that would indeed be a powerful argument.

But there are other C users, who use for-loops in other ways. I just 
took a look at my own source base. These are /some/ of the for-patterns 
I've used:

for(i = a; i < b; i++)
for(i = a; !done && b < k; i <<= 1)
for(i = a; i < b; i += c)
for(i = a; i < b - c; i++)	
for(i = a + c; i < b; i++)
for(i = a; b == c && d == e && i < f; i++)
for(i = a, --j; i < j; i++, j--)
for(i = a, j = b; i <= c; i++)
for(i = a; arr_a[i] != c && arr_b[i] != c; i++)
for(i = a; arr[i] != b; i++)
for(i = a, j = b; c == d && i > e; i >>= 1, --j)
for(p = start; p != finish; p = p->next)

These are /patterns/ of for-loop usage, not actual for-loop code: each 
one of the above represents a slightly different, or occasionally very 
different, usage of for() that /is/ to be found in my source base, and 
most of them are used quite a lot therein.

Process: find -name \*c | xargs grep "for *(" | sort > for.txt
Then I looked through for.txt for different patterns. Each time I found 
a genuinely different pattern, I summarised it (see above list).

I only got a tenth the way through the file before I got bored of it and 
gave up.

If you had your way, most of that code would be illegal. Thanks a bunch.

> This means more opportunity for error in C (in ways the language can't
> detect), plus more typing and less readability.

Powerful tools can be abused in powerful ways. If you can't refrain from 
abusing them, refrain from using them. More typing? Go on a touch-typing 
course. Less readable? I don't have a problem reading them.

> Other people's coding patterns may be different, but it's hard to
> believe that the vast majority of loops in C don't fall into one of the
> same common set of patterns.

Believe it.

> You seem to be saying the cost of C's for statement is worth it for the
> flexibility and power, even if that power is rarely needed.

I use it quite a bit, thank you.

> (In the syntax I use, I have a set of very easy dedicated loop
> constructs. But I also have a loop that works like C's for, as I found
> out yesterday because I've never used it! The point though is that you
> can have both a complex loop statement, and a simple one.)

The point is that they can be the same statement. If you want to do:

for(i = 0; i < n; i++)

nobody is going to stop you.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/23/2016 10:41:03 PM
On 23/03/16 21:18, BartC wrote:

<snip>

> Most of the rest could probably be ordinary while loops, but for some
> reason people like to obfuscate their code by using for loops for
> everthing.

Do you really, truly believe that people in this newsgroup use for() 
instead of while() because they want their code to be /harder/ to read?

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/23/2016 10:42:41 PM
On 23/03/2016 22:41, Richard Heathfield wrote:
> On 23/03/16 19:09, BartC wrote:

>> Probably at least 99% of the loops I use fall into a handful of patterns

> But there are other C users, who use for-loops in other ways. I just
> took a look at my own source base. These are /some/ of the for-patterns
> I've used:
>
> for(i = a; i < b; i++)
> for(i = a; !done && b < k; i <<= 1)
> for(i = a; i < b; i += c)
> for(i = a; i < b - c; i++)
> for(i = a + c; i < b; i++)
> for(i = a; b == c && d == e && i < f; i++)
> for(i = a, --j; i < j; i++, j--)
> for(i = a, j = b; i <= c; i++)
> for(i = a; arr_a[i] != c && arr_b[i] != c; i++)
> for(i = a; arr[i] != b; i++)
> for(i = a, j = b; c == d && i > e; i >>= 1, --j)
> for(p = start; p != finish; p = p->next)

> If you had your way, most of that code would be illegal. Thanks a bunch.

After analysing those 12 patterns, I counted 5 'straight' for-loops and 
7 ordinary while loops. So nothing desperately in need of C-for's 
flexibility unless you're keen to keep everything on one line.

And 100% belong to my list of patterns (your code is more conservative 
than mine!)

(How they might be expressed in a more crippled syntax: 
http://pastebin.com/ZGYrvJBB

In this form, they don't need any analysis.)

-- 
Bartc

0
BartC
3/24/2016 12:43:31 AM
On 24/03/16 00:43, BartC wrote:
> On 23/03/2016 22:41, Richard Heathfield wrote:
>> On 23/03/16 19:09, BartC wrote:
>
>>> Probably at least 99% of the loops I use fall into a handful of patterns
>
>> But there are other C users, who use for-loops in other ways. I just
>> took a look at my own source base. These are /some/ of the for-patterns
>> I've used:
>>
>> for(i = a; i < b; i++)
>> for(i = a; !done && b < k; i <<= 1)
>> for(i = a; i < b; i += c)
>> for(i = a; i < b - c; i++)
>> for(i = a + c; i < b; i++)
>> for(i = a; b == c && d == e && i < f; i++)
>> for(i = a, --j; i < j; i++, j--)
>> for(i = a, j = b; i <= c; i++)
>> for(i = a; arr_a[i] != c && arr_b[i] != c; i++)
>> for(i = a; arr[i] != b; i++)
>> for(i = a, j = b; c == d && i > e; i >>= 1, --j)
>> for(p = start; p != finish; p = p->next)
>
>> If you had your way, most of that code would be illegal. Thanks a bunch.
>
> After analysing those 12 patterns, I counted 5 'straight' for-loops and
> 7 ordinary while loops.

I didn't see /any/ while-loops. They're all straight for-loops, but they 
are all slightly different. Most of them start from a simple value 
(either a constant or the value of an object), but some start from a 
value that is the result of an expression. One starts with a pointer 
value. Some have multiple conditions. One has a shift instead of an 
increment, and one has a shift /as well as/ an increment. Some of them 
use array accesses in the terminating condition. Some initialise two 
objects in the first part of the for-loop, rather than just one. Many of 
these patterns cannot be duplicated by BASIC's for loop.

> And 100% belong to my list of patterns (your code is more conservative
> than mine!)

Yeah. I like my code to work, where possible. (It doesn't always, alas.)

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/24/2016 12:54:54 AM
On 3/23/2016 11:18 AM, supercat@casperkitty.com wrote:
> On Tuesday, March 22, 2016 at 7:45:10 PM UTC-5, Jerry Stuckle wrote:
>> When you get right down to it, ANY for loop is an embellished while loop.
> 
> Not necessarily.  Some compilers may seek to optimize "for" and "while"
> loops in different ways, especially if the authors believe that compilers
> should subscribe to the Principle of Least Astonishment whether or not the
> Standard requires it [a principle I would like to see return to the
> culture].  Given that the vast majority of programs in many fields are
> subject to a requirement that they must refrain from doing certain things
> no matter what input they receive, there could be considerable benefit to
> allowing programmers to give substantial freedom to compilers without giving
> them total freedom.
>

Optimization does not preclude the fact that any for loop is an
embellished while loop.

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
0
Jerry
3/24/2016 3:43:54 AM
On Wednesday, March 23, 2016 at 10:06:11 PM UTC-5, Bart wrote:
> On 23/03/2016 22:41, Richard Heathfield wrote:
> > On 23/03/16 19:09, BartC wrote:
> 
> >> Probably at least 99% of the loops I use fall into a handful of patterns
> 
> > But there are other C users, who use for-loops in other ways. I just
> > took a look at my own source base. These are /some/ of the for-patterns
> > I've used:
> >
> > for(i = a; i < b; i++)
> > for(i = a; !done && b < k; i <<= 1)
> > for(i = a; i < b; i += c)
> > for(i = a; i < b - c; i++)
> > for(i = a + c; i < b; i++)
> > for(i = a; b == c && d == e && i < f; i++)
> > for(i = a, --j; i < j; i++, j--)
> > for(i = a, j = b; i <= c; i++)
> > for(i = a; arr_a[i] != c && arr_b[i] != c; i++)
> > for(i = a; arr[i] != b; i++)
> > for(i = a, j = b; c == d && i > e; i >>= 1, --j)
> > for(p = start; p != finish; p = p->next)
> 
> > If you had your way, most of that code would be illegal. Thanks a bunch.
> 
> After analysing those 12 patterns, I counted 5 'straight' for-loops and 
> 7 ordinary while loops. So nothing desperately in need of C-for's 
> flexibility unless you're keen to keep everything on one line.
> 
> And 100% belong to my list of patterns (your code is more conservative 
> than mine!)
> 
> (How they might be expressed in a more crippled syntax: 
> http://pastebin.com/ZGYrvJBB
> 
> In this form, they don't need any analysis.)
> 

You could define a macro to expand an abbreviated, stylized
version into the standard form, and then use the macro 
everywhere. Perhaps call it proper_for or pfor, or por?

#define pfor(v,i,n) for (int v=i; v<n; ++v)

And use the standard form (if/only) when the extra 
flexibility is needed.

You could have a separate 4 argument macro if the step
needs to be changed, and dispatch to the correct macro
with PP_NARG.

#define pfors(i,s,n,t) for (int i=s; i<n; i+=t)

But these can only count /up/ (unless you put a negative
in the step, but that would be weird), so we also need
companion versions that go down.

#define nfor(v,n,i) for (int v=n-1; v>=i; --v)
#define nfor1(v,n,i) for (int v=n; v>i; --v)
#define nfors(i,n,s,t) for (int i=n-1; i>=s, --i)
#define nfors1(i,n,s,t) for (int i=n; i>s; --i)

(where I added extra variants for possibly-commonly-desire-
able variations).

Then, if none of your code actually uses the standard for
statement (not needing the flexibility), then just redefine
"for" to be the most commonly used variant.

#define for pfor

Then, before sharing any of this code online, just pass it
through the preprocessor.

cpp -P

0
luser
3/24/2016 4:26:08 AM
On Wednesday, March 23, 2016 at 10:06:08 PM UTC-5, Keith Thompson wrote:
> If I see
> 
>     for(i=0; i<view->ndim; i++) {
> 
> I'm equally certain that it's a simple iteration over a range of values
> (even though I'd add a few spaces).

Does "i" change within the loop?  How do you know?  What about view->ndim?

In many dialects of Basic, the sequence of values that will be iterated over
in the absence of an "exit" statement is set when the loop enters.  In cases
where that wouldn't be desirable, it's necessary to use some other kind of
loop, but in cases where that matches the desired behavior one need not
study the body of a loop to know whether anything will modify the current
index, step size, or ending value (none of those things can be modified, so
none of them will be).
0
supercat
3/24/2016 5:21:56 AM
On Thursday, March 24, 2016 at 3:04:53 AM UTC, Richard Heathfield wrote:
>
> What you call 'proper' for statements is entirely up to you, but you 
> haven't yet explained /why/ your view is so compelling as to require 
> everyone to change to it. All you've really said is that you prefer 
> BASIC's for to C's for. Fine, that's your prerogative, and nobody is 
> going to try to change your mind. (Well, some people will, but you don't 
> have to listen.)
> 
A counter is fundamental to a for loop. For i = 1,2,3,4,5,6 ... 100
do something with i.
Most C for loops are effectively that, but it's not enforced.
Two crucial characteristics of canonical for are 
a) a counter
b) the number of elements or passes is known at loop entry and
is immutable except by early termination.



0
Malcolm
3/24/2016 8:43:14 AM
On Thursday, March 24, 2016 at 8:43:29 AM UTC, Malcolm McLean wrote:

> A counter is fundamental to a for loop. For i = 1,2,3,4,5,6 ... 100
> do something with i.

for(p = first; p != NULL;p = p->next)
{
  // ...
}

> Two crucial characteristics of canonical for are 
> a) a counter

Uh-huh.

> b) the number of elements or passes is known at loop entry and
> is immutable except by early termination.

Uh-huh. 

"MMTATHDNU Pt VII"
0
gwowen
3/24/2016 9:47:14 AM
On 24/03/16 08:43, Malcolm McLean wrote:
> On Thursday, March 24, 2016 at 3:04:53 AM UTC, Richard Heathfield wrote:
>>
>> What you call 'proper' for statements is entirely up to you, but you
>> haven't yet explained /why/ your view is so compelling as to require
>> everyone to change to it. All you've really said is that you prefer
>> BASIC's for to C's for. Fine, that's your prerogative, and nobody is
>> going to try to change your mind. (Well, some people will, but you don't
>> have to listen.)
>>
> A counter is fundamental to a for loop.

In BASIC it is. Not in C, though. The idiom

for(p = list->first; p != NULL; p = p->next)

is common, and it's not a counter.

> For i = 1,2,3,4,5,6 ... 100
> do something with i.
> Most C for loops are effectively that, but it's not enforced.
> Two crucial characteristics of canonical for are
> a) a counter
> b) the number of elements or passes is known at loop entry and
> is immutable except by early termination.

If it truly were canonical, the C Standard (which is the very definition 
of 'canonical' for C) would enforce it, which it doesn't, so it isn't.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/24/2016 10:28:50 AM
On 24/03/16 09:47, gwowen wrote:
> On Thursday, March 24, 2016 at 8:43:29 AM UTC, Malcolm McLean wrote:
>
>> A counter is fundamental to a for loop. For i = 1,2,3,4,5,6 ... 100
>> do something with i.
>
> for(p = first; p != NULL;p = p->next)
> {
>    // ...
> }

Oops, you beat me to it.

> "MMTATHDNU Pt VII"

I get the MM. DNU might be "does not understand". But TATH???


-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/24/2016 10:30:25 AM
On Thursday, March 24, 2016 at 10:30:33 AM UTC, Richard Heathfield wrote:

> I get the MM. DNU might be "does not understand". But TATH???
> 

"... talks about things he ..."
0
gwowen
3/24/2016 10:54:30 AM
On 24/03/2016 04:26, luser droog wrote:
> On Wednesday, March 23, 2016 at 10:06:11 PM UTC-5, Bart wrote:

>> After analysing those 12 patterns, I counted 5 'straight' for-loops and
>> 7 ordinary while loops. So nothing desperately in need of C-for's
>> flexibility unless you're keen to keep everything on one line.

> You could define a macro to expand an abbreviated, stylized
> version into the standard form, and then use the macro
> everywhere. Perhaps call it proper_for or pfor, or por?
>
> #define pfor(v,i,n) for (int v=i; v<n; ++v)

> And use the standard form (if/only) when the extra
> flexibility is needed.

Yes, that was exactly what I did for a while. But such macros weren't 
popular if they popped up in code posted here:

TO (i,n) {....}                 Repeat n times
FOR (i,a,b) {....}              Iterate i over a..b
etc.

It was a great time-saver, was less fiddly to type, I could concentrate 
on the rest of the code, and also wasted less effort tracking down bugs 
like:

    for (i=0; i<m; ++i)
       (for j=0; j<n; ++i) {....}

(Because the second line was duplicated from the first, but not all the 
i's were converted to j's)

> You could have a separate 4 argument macro if the step
> needs to be changed, and dispatch to the correct macro
> with PP_NARG.
>
> #define pfors(i,s,n,t) for (int i=s; i<n; i+=t)

I think I had FORBY when the step wasn't 1, and FORD to iterate 
downwards. By I never used FORBY, only FORD once or twice.

> Then, before sharing any of this code online, just pass it
> through the preprocessor.
>
> cpp -P

gcc only seems to recognise -E, and that seems to produce a huge pile of 
crap in addition to the actual code. But it will also translate all the 
code that I want to keep as macros (most #defines for example).

-- 
Bartc
0
BartC
3/24/2016 11:43:41 AM
On 24/03/2016 09:47, gwowen wrote:
> On Thursday, March 24, 2016 at 8:43:29 AM UTC, Malcolm McLean wrote:
>
>> A counter is fundamental to a for loop. For i = 1,2,3,4,5,6 ... 100
>> do something with i.
>
> for(p = first; p != NULL;p = p->next)
> {
>    // ...
> }
>
>> Two crucial characteristics of canonical for are
>> a) a counter
>
> Uh-huh.
>
>> b) the number of elements or passes is known at loop entry and
>> is immutable except by early termination.
>
> Uh-huh.
>
> "MMTATHDNU Pt VII"
>

He understands them perfectly well. But you are only focussing on the 
narrow definition of 'for' used by C.

I first used 'for' in the sense of Malcolm's definition in the mid 70s, 
and didn't even see C's version until the 80s. I never used it until the 
90s and then only briefly.

A third characteristic he didn't mention is that the kind of for-loop 
he's talking about is a high level statement where the compiler 
generates the code required to make it work (the assignments, increments 
and compares, and makes sure it's doing this with same loop variable).

In C you have to do much of this work yourself, ie. do the compiler's 
job for it. That must be why it's 'better'!

-- 
Bartc
0
BartC
3/24/2016 11:54:22 AM
On Thursday, March 24, 2016 at 11:54:39 AM UTC, Bart wrote:

> He understands them perfectly well.

Nope.
0
gwowen
3/24/2016 12:31:47 PM
On 24/03/2016 12:31, gwowen wrote:
> On Thursday, March 24, 2016 at 11:54:39 AM UTC, Bart wrote:
>
>> He understands them perfectly well.
>
> Nope.

So what is it that he doesn't understand?

Or are you deliberately ignoring every other language in the world apart 
from C?



0
BartC
3/24/2016 1:04:10 PM
On 24/03/16 11:54, BartC wrote:

<snip>

> But you are only focussing on the
> narrow definition of 'for' used by C.

(a) This is comp.lang.c, where we are *supposed* to focus on C;
(b) I thought your complaint about C's 'for' definition was that it was 
too wide, and now you're saying it's too narrow. So, on average, it's 
about right.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/24/2016 1:12:58 PM
On 24/03/16 13:04, BartC wrote:
> On 24/03/2016 12:31, gwowen wrote:
>> On Thursday, March 24, 2016 at 11:54:39 AM UTC, Bart wrote:
>>
>>> He understands them perfectly well.
>>
>> Nope.
>
> So what is it that he doesn't understand?
>
> Or are you deliberately ignoring every other language in the world apart
> from C?

Are you deliberately ignoring the topic of this newsgroup? This is 
comp.lang.c. If you want comp.programming, you know where to find it.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
0
Richard
3/24/2016 1:16:40 PM
On Thursday, March 24, 2016 at 1:13:09 PM UTC, Richard Heathfield wrote:
> On 24/03/16 11:54, BartC wrote:
> 
> <snip>
> 
> > But you are only focussing on the
> > narrow definition of 'for' used by C.
> 
> (a) This is comp.lang.c, where we are *supposed* to focus on C;
> (b) I thought your complaint about C's 'for' definition was that it was 
> too wide, and now you're saying it's too narrow. So, on average, it's 
> about right.
> 
Obviously if you use the term "canonical for loop" in a C newsgroup, you
mean "for as understood by most other languages, except C and its derivatives".

Canonical means "as understood and established over time", e.g "the canonical
gospels", as opposed to newly composed or newly discovered material, which
might well be superior to the existing gospels in many senses, but isn't 
in the tradition.