Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #165626 > unrolled thread

Re: Memorizing C operator precedence

Started byJens Stuckelberger <Jens_Stuckelberger@nowhere.net>
First post2022-04-12 18:05 +0000
Last post2022-04-14 12:39 +0200
Articles 20 on this page of 22 — 10 participants

Back to article view | Back to comp.lang.c

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Memorizing C operator precedence Jens Stuckelberger <Jens_Stuckelberger@nowhere.net> - 2022-04-12 18:05 +0000
    Re: Memorizing C operator precedence Alan Mackenzie <acm@muc.de> - 2022-04-13 18:09 +0000
      Re: Memorizing C operator precedence Siri Cruise <chine.bleu@yahoo.com> - 2022-04-13 15:23 -0700
      Re: Memorizing C operator precedence Kaz Kylheku <480-992-1380@kylheku.com> - 2022-04-13 23:36 +0000
      Re: Memorizing C operator precedence Kaz Kylheku <480-992-1380@kylheku.com> - 2022-04-13 23:48 +0000
        Re: Memorizing C operator precedence Alan Mackenzie <acm@muc.de> - 2022-04-14 10:38 +0000
          Re: Memorizing C operator precedence Kaz Kylheku <480-992-1380@kylheku.com> - 2022-04-14 21:05 +0000
          Re: Memorizing C operator precedence Alan Mackenzie <acm@muc.de> - 2022-04-16 14:27 +0000
            Re: Memorizing C operator precedence Paul N <gw7rib@aol.com> - 2022-04-23 10:23 -0700
              Re: Memorizing C operator precedence Alan Mackenzie <acm@muc.de> - 2022-04-25 10:21 +0000
                Re: Memorizing C operator precedence Vir Campestris <vir.campestris@invalid.invalid> - 2022-04-25 16:43 +0100
                  Re: Memorizing C operator precedence Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-04-26 03:02 -0700
                  Re: Memorizing C operator precedence Kaz Kylheku <480-992-1380@kylheku.com> - 2022-04-26 13:58 +0000
              Re: Memorizing C operator precedence Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-04-25 14:48 -0700
          Re: Memorizing C operator precedence Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-04-25 15:16 -0700
            Re: Memorizing C operator precedence Alan Mackenzie <acm@muc.de> - 2022-04-26 10:34 +0000
              Re: Memorizing C operator precedence Ben <ben.usenet@bsb.me.uk> - 2022-04-26 13:13 +0100
                Re: Memorizing C operator precedence Alan Mackenzie <acm@muc.de> - 2022-04-26 17:25 +0000
              Re: Memorizing C operator precedence Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-04-26 06:12 -0700
                Re: Memorizing C operator precedence Alan Mackenzie <acm@muc.de> - 2022-04-26 17:17 +0000
              Re: Memorizing C operator precedence Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-04-30 07:05 -0700
      Re: Memorizing C operator precedence David Brown <david.brown@hesbynett.no> - 2022-04-14 12:39 +0200

Page 1 of 2  [1] 2  Next page →


#165626 — Re: Memorizing C operator precedence

FromJens Stuckelberger <Jens_Stuckelberger@nowhere.net>
Date2022-04-12 18:05 +0000
SubjectRe: Memorizing C operator precedence
Message-ID<t34f1f$s4u$1@gioia.aioe.org>
On 12 Apr 2022 13:03:39 GMT, Stefan Ram wrote:

> [...]

	What for? Use parentheses - that's what they are there for.

[toc] | [next] | [standalone]


#165660

FromAlan Mackenzie <acm@muc.de>
Date2022-04-13 18:09 +0000
Message-ID<t373kj$1avk$1@news.muc.de>
In reply to#165626
Jens Stuckelberger <Jens_Stuckelberger@nowhere.net> wrote:
> On 12 Apr 2022 13:03:39 GMT, Stefan Ram wrote:

>> [...]

>         What for? Use parentheses - that's what they are there for.

If you want to use parentheses, you should be writing in Lisp.  ;-)

Too many parentheses can make C code difficult to read.  Difficult to
read translates to "more bugs".  A knowledge of C's precedence levels,
at least to a moderate degree, can help avoid such bugs.

Maybe some day we'll get the compiler warning "unnecessary parentheses".

-- 
Alan Mackenzie (Nuremberg, Germany).

[toc] | [prev] | [next] | [standalone]


#165667

FromSiri Cruise <chine.bleu@yahoo.com>
Date2022-04-13 15:23 -0700
Message-ID<chine.bleu-839F13.15232913042022@reader.eternal-september.org>
In reply to#165660
In article <t373kj$1avk$1@news.muc.de>,
 Alan Mackenzie <acm@muc.de> wrote:

> Too many parentheses can make C code difficult to read.  Difficult to
> read translates to "more bugs".  A knowledge of C's precedence levels,
> at least to a moderate degree, can help avoid such bugs.

Not if you insert line breaks and indentation to line up openners 
and closers.

-- 
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted.    @
'I desire mercy, not sacrifice.'                                    /|\
Discordia: not just a religion but also a parody. This post         / \
I am an Andrea Doria sockpuppet.                  insults Islam.  Mohammed

[toc] | [prev] | [next] | [standalone]


#165672

FromKaz Kylheku <480-992-1380@kylheku.com>
Date2022-04-13 23:36 +0000
Message-ID<20220413162441.432@kylheku.com>
In reply to#165660
On 2022-04-13, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
> Alan Mackenzie <acm@muc.de> writes:
>>Too many parentheses can make C code difficult to read.  Difficult to
>>read translates to "more bugs".  A knowledge of C's precedence levels,
>>at least to a moderate degree, can help avoid such bugs.
>
>   When I would see an expression such as "( 3 * x )+ t", I might spend
>   some time wondering about why the redundant parentheses are there!

Maybe it was copy and pasted from a macro expansion, where 3 * x
had come in as an argument.

Extra parens can help with indentation when an expression
is broken up into multiple lines.

given:

     a*b*c*d*... + m*n*o*p* + ...

we might do this at first

     a*b*c*d*... +
     m*n*o*p*... +
     ...

the terms of the addition go on separate lines. Now suppose
the terms themselves are too long: now what?

     a*b*c*
     d*... +
     m*n*
     o*p*... +
     ...

that's not very good; extra parens improve it.

     (a*b*c*d*...) +
     (m*n*o*p*...) +
     (...)

then:

     (a*b*c*
      d*...) +
     (m*n*o
      *p*...) +
     (...)

Chances are your editor will handle this automatically.

[toc] | [prev] | [next] | [standalone]


#165673

FromKaz Kylheku <480-992-1380@kylheku.com>
Date2022-04-13 23:48 +0000
Message-ID<20220413163721.82@kylheku.com>
In reply to#165660
On 2022-04-13, Alan Mackenzie <acm@muc.de> wrote:
> Jens Stuckelberger <Jens_Stuckelberger@nowhere.net> wrote:
>> On 12 Apr 2022 13:03:39 GMT, Stefan Ram wrote:
>
>>> [...]
>
>>         What for? Use parentheses - that's what they are there for.
>
> If you want to use parentheses, you should be writing in Lisp.  ;-)

When you write in Lisp, most of the formatting is automatic and almost
always looks good, so you can concentrate on coding.

There are some new developments in this area in the last few years,
like the "parinfer" algorithm. "parinfer" creates a two-way linkage
between indentation and parentheses. Write your code, adjusting
indentation as you go, and the right parentheses materialize
automatically. Or, tweak the parentheses and the indentation fixes
itself accordingly. Google for demos of this.
>
> Too many parentheses can make C code difficult to read.  Difficult to
> read translates to "more bugs".  A knowledge of C's precedence levels,
> at least to a moderate degree, can help avoid such bugs.

Too much complexity in one expression makes it hard to read. Other
than breaking it up into smaller expression, what can help is to
split it into multiple lines and use indentation.

Parenthesized expressions are much more amenable for splitting across
lines and indenting than pure infix operator expressions.

-- 
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

[toc] | [prev] | [next] | [standalone]


#165685

FromAlan Mackenzie <acm@muc.de>
Date2022-04-14 10:38 +0000
Message-ID<t38tjs$cnl$1@news.muc.de>
In reply to#165673
Kaz Kylheku <480-992-1380@kylheku.com> wrote:
> On 2022-04-13, Alan Mackenzie <acm@muc.de> wrote:
>> Jens Stuckelberger <Jens_Stuckelberger@nowhere.net> wrote:
>>> On 12 Apr 2022 13:03:39 GMT, Stefan Ram wrote:
>>
>>>> [...]

>>>         What for? Use parentheses - that's what they are there for.

>> If you want to use parentheses, you should be writing in Lisp.  ;-)

> When you write in Lisp, most of the formatting is automatic and almost
> always looks good, so you can concentrate on coding.

Yes.

> There are some new developments in this area in the last few years,
> like the "parinfer" algorithm. "parinfer" creates a two-way linkage
> between indentation and parentheses. Write your code, adjusting
> indentation as you go, and the right parentheses materialize
> automatically. Or, tweak the parentheses and the indentation fixes
> itself accordingly. Google for demos of this.

I think that would drive me crazy!

>> Too many parentheses can make C code difficult to read.  Difficult to
>> read translates to "more bugs".  A knowledge of C's precedence levels,
>> at least to a moderate degree, can help avoid such bugs.

> Too much complexity in one expression makes it hard to read. Other
> than breaking it up into smaller expression, what can help is to
> split it into multiple lines and use indentation.

This is a common attitude, and I'm sure it is wrong a lot of the time.
Breaking up a complicated expression _fragments_ it - it spreads it over
a greater number of source code lines, some of which may not be visible
on the screen.  While each fragment may in itself be easier to read, the
entire expression has become more difficult.

> Parenthesized expressions are much more amenable for splitting across
> lines and indenting than pure infix operator expressions.

I'm not sure I agree with this, my background being the maintainer of
Emacs's CC Mode.

How about a real world example?  In the following (from Emacs's
syntax.c):

      if (code == Sendcomment
          && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style
          && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ?
              (nesting > 0 && --nesting == 0) : nesting < 0)
          && !comment_ender_quoted (from, from_byte, syntax))

, which is a moderately complicated example, extra parentheses around
the operands of the &&s would clutter up the code rather than clarifying
it.  Yet the whole expression being on just five lines makes it
relatively easy to understand.

> -- 
> TXR Programming Language: http://nongnu.org/txr
> Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

-- 
Alan Mackenzie (Nuremberg, Germany).

[toc] | [prev] | [next] | [standalone]


#165702

FromKaz Kylheku <480-992-1380@kylheku.com>
Date2022-04-14 21:05 +0000
Message-ID<20220414134305.103@kylheku.com>
In reply to#165685
On 2022-04-14, Alan Mackenzie <acm@muc.de> wrote:
> Kaz Kylheku <480-992-1380@kylheku.com> wrote:
>> On 2022-04-13, Alan Mackenzie <acm@muc.de> wrote:
>>> Jens Stuckelberger <Jens_Stuckelberger@nowhere.net> wrote:
>>>> On 12 Apr 2022 13:03:39 GMT, Stefan Ram wrote:
>>>
>>>>> [...]
>
>>>>         What for? Use parentheses - that's what they are there for.
>
>>> If you want to use parentheses, you should be writing in Lisp.  ;-)
>
>> When you write in Lisp, most of the formatting is automatic and almost
>> always looks good, so you can concentrate on coding.
>
> Yes.
>
>> There are some new developments in this area in the last few years,
>> like the "parinfer" algorithm. "parinfer" creates a two-way linkage
>> between indentation and parentheses. Write your code, adjusting
>> indentation as you go, and the right parentheses materialize
>> automatically. Or, tweak the parentheses and the indentation fixes
>> itself accordingly. Google for demos of this.
>
> I think that would drive me crazy!
>
>>> Too many parentheses can make C code difficult to read.  Difficult to
>>> read translates to "more bugs".  A knowledge of C's precedence levels,
>>> at least to a moderate degree, can help avoid such bugs.
>
>> Too much complexity in one expression makes it hard to read. Other
>> than breaking it up into smaller expression, what can help is to
>> split it into multiple lines and use indentation.
>
> This is a common attitude, and I'm sure it is wrong a lot of the time.
> Breaking up a complicated expression _fragments_ it - it spreads it over
> a greater number of source code lines, some of which may not be visible
> on the screen.

A large expression won't be visible all at once, eithery way; if it is on
too few lines, they end up long. If we have multiple choices about
how to break it up, we can achieve a best fit.

> While each fragment may in itself be easier to read, the
> entire expression has become more difficult.
>
>> Parenthesized expressions are much more amenable for splitting across
>> lines and indenting than pure infix operator expressions.
>
> I'm not sure I agree with this, my background being the maintainer of
> Emacs's CC Mode.
>
> How about a real world example?  In the following (from Emacs's
> syntax.c):
>
>       if (code == Sendcomment
>           && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style
>           && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ?
>               (nesting > 0 && --nesting == 0) : nesting < 0)
>           && !comment_ender_quoted (from, from_byte, syntax))

Interestingly, you have unnecessary parentheses there, in the ternary:

  a ? (b) : c

b is already flanked by a ? opener and : closer. I will keep those,
and for consistency parenthesize the (c) also.

> , which is a moderately complicated example, extra parentheses around
> the operands of the &&s would clutter up the code rather than clarifying
> it.  Yet the whole expression being on just five lines makes it
> relatively easy to understand.

Proposal:

       if ((code == Sendcomment) &&
           (SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style) &&
           (SYNTAX_FLAGS_COMMENT_NESTED (syntax)
            ? (nesting > 0 && --nesting == 0)
            : (nesting < 0)) &&
           (!comment_ender_quoted (from, from_byte, syntax)))

There is now consistent alignment. When we scan the left edge, we
don't see funny business like:

   code ==
   (SYNTAX...
   SYNTAX..

I find that the infix operators are best put at the end of the previous
line, so that the left edge always begins with an operand, where we can
have a parenthesis for promoting alignment.

This can be visualized in chunks like this:

       if ((...................) &&
           (...............................................) &&
           (....................................
            ? (.............................)
            : (...........)) &&
           (!.............................................)))

It is a regret that the && operators are not vertically aligned.

Not knowing quite where to put the infix operators is just the scourge
of infix:

   (if (and (eq code 'sendcomment)
            (eq (syntax-flags-comment-style syntax 0) 'style)
            (if (syntax-flags-comment-nested syntax)
              (if (plusp nesting) (zerop (dec nesting)))
              (minus nesting))
            (not (comment-gender-quoted from from-byte syntax)))
     (then-do-this))

No neet to repeat the "and": just write it once and give it arguments.
line by line, indented to the same column.

If we want to be slightly sneaky, we take advantage of and being a
generalization of if:

   (and (eq code 'sendcomment)
        (eq (syntax-flags-comment-style syntax 0) 'style)
        (if (syntax-flags-comment-nested syntax)
          (if (plusp nesting) (zerop (dec nesting)))
          (minus nesting))
        (not (comment-gender-quoted from from-byte syntax))
        (then-do-this))


-- 
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

[toc] | [prev] | [next] | [standalone]


#165713

FromAlan Mackenzie <acm@muc.de>
Date2022-04-16 14:27 +0000
Message-ID<t3ejp3$2ch3$1@news.muc.de>
In reply to#165685
Stefan Ram <ram@zedat.fu-berlin.de> wrote:
> Alan Mackenzie <acm@muc.de> writes:
>>Breaking up a complicated expression _fragments_ it

>   Example for the refactor "extract variable" in pseudocode:

> return quantity * item_price -
>   max(0, quantity - 500) * item_price * 0.05 +
>   min(quantity * item_price * 0.1, 100);

>   ------------------>

> const base_price = quantity * item_price;
> const quantity_discount = 
> max( 0, quantity - 500 )* item_price * 0.05;
> const shipping = min( base_price * 0.1, 100 );
> return base_price - quantity_discount + shipping;

>   . There is no reason to fall behind the state of the art.

Whatever that might be in this particular matter.  In your rearrangement
of code, you have doubled its size.  You have increased the number of
operators used from 8 to 10, the number of lines of code from 3 to 5 and
the number of statements from 1 to 4.

Other things being equal, a more concise expression is easier to
understand.  No doubt you would here argue that the other things aren't
equal, and I agree there is some merit to that argument.

But the 5-line version is primarily easier for beginners to understand,
who mentally break down program text to smaller units.  An experienced
programmer will prefer the 1-statement version - on encountering the
4-statement version she will subconsciously remark "do I have to go
through all this verbiage _again_?".

>   Suggested reading:

> Refactoring - Improving the Design of Existing Code
> by Martin Fowler,
> publishing house Addison-Wesley Educational Publishers Inc.

>   . Don't worry! It is written in an easy-to-understand way
>   so that most programmers can get it.

No worries!  I've had a copy of this book for many years, though it's
some time since I've read it.  Just because one can refactor code doesn't
mean it's necessarily a good thing to do.  Often it is.  I think it was
Steve Yegge in one of his blogs who noted that the problem with
refactoring is that it often bloats code size.

-- 
Alan Mackenzie (Nuremberg, Germany).

[toc] | [prev] | [next] | [standalone]


#165879

FromPaul N <gw7rib@aol.com>
Date2022-04-23 10:23 -0700
Message-ID<6295432d-6ca9-49ea-b29c-858de4b65b75n@googlegroups.com>
In reply to#165713
On Saturday, April 16, 2022 at 3:28:00 PM UTC+1, Alan Mackenzie wrote:
> Stefan Ram <r...@zedat.fu-berlin.de> wrote: 
> > Alan Mackenzie <a...@muc.de> writes:
> >>Breaking up a complicated expression _fragments_ it
> > Example for the refactor "extract variable" in pseudocode: 
> 
> > return quantity * item_price - 
> > max(0, quantity - 500) * item_price * 0.05 + 
> > min(quantity * item_price * 0.1, 100); 
> 
> > ------------------> 
> 
> > const base_price = quantity * item_price; 
> > const quantity_discount = 
> > max( 0, quantity - 500 )* item_price * 0.05; 
> > const shipping = min( base_price * 0.1, 100 ); 
> > return base_price - quantity_discount + shipping; 

How about a compromise?

return quantity * item_price
- max(0, quantity - 500) * item_price * 0.05  // quantity discount
+ min(quantity * item_price * 0.1, 100);  // shipping

[toc] | [prev] | [next] | [standalone]


#165916

FromAlan Mackenzie <acm@muc.de>
Date2022-04-25 10:21 +0000
Message-ID<t45sne$2r7r$1@news.muc.de>
In reply to#165879
Paul N <gw7rib@aol.com> wrote:
> On Saturday, April 16, 2022 at 3:28:00 PM UTC+1, Alan Mackenzie wrote:
>> Stefan Ram <r...@zedat.fu-berlin.de> wrote: 
>> > Alan Mackenzie <a...@muc.de> writes:
>> >>Breaking up a complicated expression _fragments_ it
>> > Example for the refactor "extract variable" in pseudocode: 

>> > return quantity * item_price - 
>> > max(0, quantity - 500) * item_price * 0.05 + 
>> > min(quantity * item_price * 0.1, 100); 

>> > ------------------> 

>> > const base_price = quantity * item_price; 
>> > const quantity_discount = 
>> > max( 0, quantity - 500 )* item_price * 0.05; 
>> > const shipping = min( base_price * 0.1, 100 ); 
>> > return base_price - quantity_discount + shipping; 

> How about a compromise?

> return quantity * item_price
> - max(0, quantity - 500) * item_price * 0.05  // quantity discount
> + min(quantity * item_price * 0.1, 100);  // shipping

I think that is the best of all!  Inserting brief, meaningful comments,
as above, makes the thing easy to understand without bloating the code.
I wish more people would code like this.

-- 
Alan Mackenzie (Nuremberg, Germany).

[toc] | [prev] | [next] | [standalone]


#165921

FromVir Campestris <vir.campestris@invalid.invalid>
Date2022-04-25 16:43 +0100
Message-ID<t46fih$qkr$1@dont-email.me>
In reply to#165916
On 25/04/2022 11:21, Alan Mackenzie wrote:
> I think that is the best of all!  Inserting brief, meaningful comments,
> as above, makes the thing easy to understand without bloating the code.
> I wish more people would code like this.

Absolutely.

It has the great advantage that the comments say what the code is 
_supposed_ to do. If they disagree that's a great big alarm bell to 
anyone looking for bugs.

"self documenting code" doesn't do that.

Andy

[toc] | [prev] | [next] | [standalone]


#165938

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2022-04-26 03:02 -0700
Message-ID<fcd20f44-525f-42da-b95b-301433a22ad5n@googlegroups.com>
In reply to#165921
On Monday, 25 April 2022 at 16:43:25 UTC+1, Vir Campestris wrote:
> On 25/04/2022 11:21, Alan Mackenzie wrote: 
> > I think that is the best of all! Inserting brief, meaningful comments, 
> > as above, makes the thing easy to understand without bloating the code. 
> > I wish more people would code like this.
> Absolutely. 
> 
> It has the great advantage that the comments say what the code is 
> _supposed_ to do. If they disagree that's a great big alarm bell to 
> anyone looking for bugs. 
> 
> "self documenting code" doesn't do that. 
> 
However code tends to change over time. Since the compiler has no way
of understanding the comments, it can't warn when a comment is not
updated to reflect a change in the code. 
If you have a "self-documenting" language or system, like Doxygen, which
ties comments to code features, then you can issue such warnings.

[toc] | [prev] | [next] | [standalone]


#165943

FromKaz Kylheku <480-992-1380@kylheku.com>
Date2022-04-26 13:58 +0000
Message-ID<20220426065706.709@kylheku.com>
In reply to#165921
On 2022-04-25, Vir Campestris <vir.campestris@invalid.invalid> wrote:
> On 25/04/2022 11:21, Alan Mackenzie wrote:
>> I think that is the best of all!  Inserting brief, meaningful comments,
>> as above, makes the thing easy to understand without bloating the code.
>> I wish more people would code like this.
>
> Absolutely.
>
> It has the great advantage that the comments say what the code is 
> _supposed_ to do. If they disagree that's a great big alarm bell to 
> anyone looking for bugs.
>
> "self documenting code" doesn't do that.

I will take a set of test cases that break right away, over some comment
that started lying 13 years ago, but nobody noticed untl now.

-- 
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

[toc] | [prev] | [next] | [standalone]


#165934

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-04-25 14:48 -0700
Message-ID<86pml46dhb.fsf@linuxsc.com>
In reply to#165879
Paul N <gw7rib@aol.com> writes:

> On Saturday, April 16, 2022 at 3:28:00 PM UTC+1, Alan Mackenzie wrote:
>
>> Stefan Ram <r...@zedat.fu-berlin.de> wrote:
>>
>>> Alan Mackenzie <a...@muc.de> writes:
>>>
>>>> Breaking up a complicated expression _fragments_ it
>>>
>>> Example for the refactor "extract variable" in pseudocode:
>>>
>>> return quantity * item_price -
>>> max(0, quantity - 500) * item_price * 0.05 +
>>> min(quantity * item_price * 0.1, 100);
>>>
>>> ------------------>
>>>
>>> const base_price = quantity * item_price;
>>> const quantity_discount =
>>> max( 0, quantity - 500 )* item_price * 0.05;
>>> const shipping = min( base_price * 0.1, 100 );
>>> return base_price - quantity_discount + shipping;
>
> How about a compromise?
>
> return quantity * item_price
> - max(0, quantity - 500) * item_price * 0.05  // quantity discount
> + min(quantity * item_price * 0.1, 100);  // shipping

Speaking for myself I would rather see something like this:

   [...]
        unsigned n = quantity;
        double price = item_price;
        return  sale_charge( n, price ) + shipping_charge( n, price );


    double
    sale_charge( unsigned n, double price ){
        return  base_charge( n, price ) - quantity_discount( n, price );
    }

    double
    shipping_charge( unsigned n, double price ){
        return  min( base_charge( n, price ) * 0.1, 100.0 );
    }

    double
    base_charge( unsigned n, double price ){
        return  n * price;
    }

    double
    quantity_discount( unsigned n, double price ){
        return  n > 500 ? (n-500) * price * 0.05  :  0;
    }

[toc] | [prev] | [next] | [standalone]


#165935

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-04-25 15:16 -0700
Message-ID<86levs6c6n.fsf@linuxsc.com>
In reply to#165685
Alan Mackenzie <acm@muc.de> writes:

> Kaz Kylheku <480-992-1380@kylheku.com> wrote:
>
>> On 2022-04-13, Alan Mackenzie <acm@muc.de> wrote:

[...]

>>> Too many parentheses can make C code difficult to read.  Difficult
>>> to read translates to "more bugs".  A knowledge of C's precedence
>>> levels, at least to a moderate degree, can help avoid such bugs.

I definitely agree with this.

>> Too much complexity in one expression makes it hard to read.

I also agree with this.

>> Other
>> than breaking it up into smaller expression, what can help is to
>> split it into multiple lines and use indentation.

Sometimes, but rarely.  In most cases another choice is better.

> This is a common attitude, and I'm sure it is wrong a lot of the time.
> Breaking up a complicated expression _fragments_ it - it spreads it over
> a greater number of source code lines, some of which may not be visible
> on the screen.  While each fragment may in itself be easier to read, the
> entire expression has become more difficult.
>
>> Parenthesized expressions are much more amenable for splitting across
>> lines and indenting than pure infix operator expressions.

Yuck.  Any expression complicated enough to need parentheses
_and_ multiple lines _and_ some indication of nesting merits
rewriting into simpler components.

> I'm not sure I agree with this, my background being the maintainer of
> Emacs's CC Mode.
>
> How about a real world example?  In the following (from Emacs's
> syntax.c):
>
>       if (code == Sendcomment
>           && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style
>           && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ?
>               (nesting > 0 && --nesting == 0) : nesting < 0)
>           && !comment_ender_quoted (from, from_byte, syntax))
>
> , which is a moderately complicated example, extra parentheses around
> the operands of the &&s would clutter up the code rather than clarifying
> it.  Yet the whole expression being on just five lines makes it
> relatively easy to understand.

I'm a longtime emacs user, and definitely a fan, but this code
is horrible, on several different levels.  I agree that adding
extra parentheses around the &&s operands would make things
worse, but it's already way below threshold for any reasonable
standard of code review.

Just my unabashed impressions..  :)

[toc] | [prev] | [next] | [standalone]


#165939

FromAlan Mackenzie <acm@muc.de>
Date2022-04-26 10:34 +0000
Message-ID<t48hs2$urk$1@news.muc.de>
In reply to#165935
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> Alan Mackenzie <acm@muc.de> writes:

>> Kaz Kylheku <480-992-1380@kylheku.com> wrote:

>>> On 2022-04-13, Alan Mackenzie <acm@muc.de> wrote:

> [...]

>>>> Too many parentheses can make C code difficult to read.  Difficult
>>>> to read translates to "more bugs".  A knowledge of C's precedence
>>>> levels, at least to a moderate degree, can help avoid such bugs.

> I definitely agree with this.

>>> Too much complexity in one expression makes it hard to read.

> I also agree with this.

>>> Other
>>> than breaking it up into smaller expression, what can help is to
>>> split it into multiple lines and use indentation.

> Sometimes, but rarely.  In most cases another choice is better.

>> This is a common attitude, and I'm sure it is wrong a lot of the time.
>> Breaking up a complicated expression _fragments_ it - it spreads it over
>> a greater number of source code lines, some of which may not be visible
>> on the screen.  While each fragment may in itself be easier to read, the
>> entire expression has become more difficult.

>>> Parenthesized expressions are much more amenable for splitting across
>>> lines and indenting than pure infix operator expressions.

> Yuck.  Any expression complicated enough to need parentheses
> _and_ multiple lines _and_ some indication of nesting merits
> rewriting into simpler components.

That was my point.  Such rewriting bloats code, making it more difficult,
as a whole, to understand.

>> I'm not sure I agree with this, my background being the maintainer of
>> Emacs's CC Mode.

>> How about a real world example?  In the following (from Emacs's
>> syntax.c):

>>       if (code == Sendcomment
>>           && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style
>>           && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ?
>>               (nesting > 0 && --nesting == 0) : nesting < 0)
>>           && !comment_ender_quoted (from, from_byte, syntax))

>> , which is a moderately complicated example, extra parentheses around
>> the operands of the &&s would clutter up the code rather than
>> clarifying it.  Yet the whole expression being on just five lines
>> makes it relatively easy to understand.

> I'm a longtime emacs user, and definitely a fan, but this code
> is horrible, on several different levels.

I disagree.  The condition being coded is "horrible", so the code cannot
be "nice".  That condition is testing whether an ostensible comment ender
actually ends a comment.  There are several things to test, namely,
that we're not trying to end a // comment with */, that the comment, if
nested (this can happen, for example, in Lisp or Pascal), reaches the
outer level of nesting, and that the comment ender isn't quoted.

> I agree that adding extra parentheses around the &&s operands would
> make things worse, ....

Agreed.

> .... but it's already way below threshold for any reasonable standard
> of code review.

This is simply untrue.  That piece of code has been reviewed many times,
including by me, and presents no particular difficulties in
understanding.

I don't think it could be written better.

> Just my unabashed impressions..  :)

-- 
Alan Mackenzie (Nuremberg, Germany).

[toc] | [prev] | [next] | [standalone]


#165940

FromBen <ben.usenet@bsb.me.uk>
Date2022-04-26 13:13 +0100
Message-ID<871qxkqbyj.fsf@bsb.me.uk>
In reply to#165939
Alan Mackenzie <acm@muc.de> writes:

> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>> Alan Mackenzie <acm@muc.de> writes:

>>> How about a real world example?  In the following (from Emacs's
>>> syntax.c):
>
>>>       if (code == Sendcomment
>>>           && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style
>>>           && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ?
>>>               (nesting > 0 && --nesting == 0) : nesting < 0)
>>>           && !comment_ender_quoted (from, from_byte, syntax))
>
>>> , which is a moderately complicated example, extra parentheses around
>>> the operands of the &&s would clutter up the code rather than
>>> clarifying it.  Yet the whole expression being on just five lines
>>> makes it relatively easy to understand.
>
>> I'm a longtime emacs user, and definitely a fan, but this code
>> is horrible, on several different levels.
>
> I disagree.  The condition being coded is "horrible", so the code cannot
> be "nice".  That condition is testing whether an ostensible comment ender
> actually ends a comment.  There are several things to test, namely,
> that we're not trying to end a // comment with */, that the comment, if
> nested (this can happen, for example, in Lisp or Pascal), reaches the
> outer level of nesting, and that the comment ender isn't quoted.
>
>> I agree that adding extra parentheses around the &&s operands would
>> make things worse, ....
>
> Agreed.
>
>> .... but it's already way below threshold for any reasonable standard
>> of code review.
>
> This is simply untrue.  That piece of code has been reviewed many times,
> including by me, and presents no particular difficulties in
> understanding.
>
> I don't think it could be written better.

One concern is that this is not a plain condition since it sometimes has
side effects.  I'm comfortable with trivial cases of that (while (*cp++)
... for example) but there is more to check here.  For example, it's not
obvious that the conditional decrement must not happen when the rather
opaque condition

  SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style

is false.

And I also find myself wondering why the value of nesting is significant
when SYNTAX_FLAGS_COMMENT_NESTED (syntax) is false.  Is it playing some
dual role?

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#165951

FromAlan Mackenzie <acm@muc.de>
Date2022-04-26 17:25 +0000
Message-ID<t499v1$13fs$2@news.muc.de>
In reply to#165940
Ben <ben.usenet@bsb.me.uk> wrote:
> Alan Mackenzie <acm@muc.de> writes:

>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>> Alan Mackenzie <acm@muc.de> writes:

>>>> How about a real world example?  In the following (from Emacs's
>>>> syntax.c):

>>>>       if (code == Sendcomment
>>>>           && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style
>>>>           && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ?
>>>>               (nesting > 0 && --nesting == 0) : nesting < 0)
>>>>           && !comment_ender_quoted (from, from_byte, syntax))

>>>> , which is a moderately complicated example, extra parentheses around
>>>> the operands of the &&s would clutter up the code rather than
>>>> clarifying it.  Yet the whole expression being on just five lines
>>>> makes it relatively easy to understand.

>>> I'm a longtime emacs user, and definitely a fan, but this code
>>> is horrible, on several different levels.

>> I disagree.  The condition being coded is "horrible", so the code cannot
>> be "nice".  That condition is testing whether an ostensible comment ender
>> actually ends a comment.  There are several things to test, namely,
>> that we're not trying to end a // comment with */, that the comment, if
>> nested (this can happen, for example, in Lisp or Pascal), reaches the
>> outer level of nesting, and that the comment ender isn't quoted.

>>> I agree that adding extra parentheses around the &&s operands would
>>> make things worse, ....

>> Agreed.

>>> .... but it's already way below threshold for any reasonable standard
>>> of code review.

>> This is simply untrue.  That piece of code has been reviewed many times,
>> including by me, and presents no particular difficulties in
>> understanding.

>> I don't think it could be written better.

> One concern is that this is not a plain condition since it sometimes
> has side effects.  I'm comfortable with trivial cases of that (while
> (*cp++) ... for example) but there is more to check here.  For example,
> it's not obvious that the conditional decrement must not happen when
> the rather opaque condition

>   SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style

> is false.

That condition just checks that we're not trying to close a C line
comment with a */, for example.

> And I also find myself wondering why the value of nesting is significant
> when SYNTAX_FLAGS_COMMENT_NESTED (syntax) is false.  Is it playing some
> dual role?

Yes, unfortunately so.  There's an ad-hoc convention where this variable
is -1 in non-nested comments.  It plays a role where there are both
nested and non-nested comments in a language (such as Common Lisp).

> -- 
> Ben.

-- 
Alan Mackenzie (Nuremberg, Germany).

[toc] | [prev] | [next] | [standalone]


#165941

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2022-04-26 06:12 -0700
Message-ID<c170f4ee-4c90-4291-af8b-478f98862cbfn@googlegroups.com>
In reply to#165939
On Tuesday, 26 April 2022 at 11:34:55 UTC+1, Alan Mackenzie wrote:
> Tim Rentsch <tr.1...@z991.linuxsc.com> wrote: 
> > Alan Mackenzie <a...@muc.de> writes: 
> 
> >> Kaz Kylheku <480-99...@kylheku.com> wrote: 
> 
> >>> On 2022-04-13, Alan Mackenzie <a...@muc.de> wrote: 
> 
> > [...] 
> 
> >>>> Too many parentheses can make C code difficult to read. Difficult 
> >>>> to read translates to "more bugs". A knowledge of C's precedence 
> >>>> levels, at least to a moderate degree, can help avoid such bugs. 
> 
> > I definitely agree with this. 
> 
> >>> Too much complexity in one expression makes it hard to read. 
> 
> > I also agree with this. 
> 
> >>> Other 
> >>> than breaking it up into smaller expression, what can help is to 
> >>> split it into multiple lines and use indentation. 
> 
> > Sometimes, but rarely. In most cases another choice is better. 
> 
> >> This is a common attitude, and I'm sure it is wrong a lot of the time. 
> >> Breaking up a complicated expression _fragments_ it - it spreads it over 
> >> a greater number of source code lines, some of which may not be visible 
> >> on the screen. While each fragment may in itself be easier to read, the 
> >> entire expression has become more difficult. 
> 
> >>> Parenthesized expressions are much more amenable for splitting across 
> >>> lines and indenting than pure infix operator expressions. 
> 
> > Yuck. Any expression complicated enough to need parentheses 
> > _and_ multiple lines _and_ some indication of nesting merits 
> > rewriting into simpler components.
> That was my point. Such rewriting bloats code, making it more difficult, 
> as a whole, to understand.
> >> I'm not sure I agree with this, my background being the maintainer of 
> >> Emacs's CC Mode. 
> 
> >> How about a real world example? In the following (from Emacs's 
> >> syntax.c): 
> 
> >> if (code == Sendcomment 
> >> && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style 
> >> && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ? 
> >> (nesting > 0 && --nesting == 0) : nesting < 0) 
> >> && !comment_ender_quoted (from, from_byte, syntax)) 
> 
> >> , which is a moderately complicated example, extra parentheses around 
> >> the operands of the &&s would clutter up the code rather than 
> >> clarifying it. Yet the whole expression being on just five lines 
> >> makes it relatively easy to understand. 
> 
> > I'm a longtime emacs user, and definitely a fan, but this code 
> > is horrible, on several different levels.
> I disagree. The condition being coded is "horrible", so the code cannot 
> be "nice". That condition is testing whether an ostensible comment ender 
> actually ends a comment. There are several things to test, namely, 
> that we're not trying to end a // comment with */, that the comment, if 
> nested (this can happen, for example, in Lisp or Pascal), reaches the 
> outer level of nesting, and that the comment ender isn't quoted.
> > I agree that adding extra parentheses around the &&s operands would
> > make things worse, .... 
> 
> Agreed. 
> 
> > .... but it's already way below threshold for any reasonable standard 
> > of code review. 
> 
> This is simply untrue. That piece of code has been reviewed many times, 
> including by me, and presents no particular difficulties in 
> understanding. 
> 
> I don't think it could be written better.
>
/*
  Does a comment ender token actually end a comment?
  Params: code - the token (e.g. Sendcomment, Receivecomment [Malcolm ??])
                  syntax - syntax flags for current comment style (see SYNTAX_FLAGS)
                  style - current comment style [Malcolm, how does this differ from syntax?]
                  nesting - nesting level (note can be negative [Malcolm, explain how])
                  from - start of comment 
                  from_byte - [Malcolm ???]  
   Returns: true if the comment ends, else false. 
*/ 
bool is_comment_ended(int code, unsigned int syntax, unsigned int style, int nesting, char *from, char from_byte)
{
    if (code != Sendcomment)
       return false;  // Not an end comment token
   if (SYNTAX_FLAGS_COMMENT_STYLE(syntax, 0) != style)
      return false; // Wrong comment style
   if (SYNTAX_FLAGS_COMMENT_NESTED(syntax))
   {
       if (nesting != 1)
         return false;  // in a nested comment
   }
  else
  {
     if (nesting < 0)
        return false; // [Malcolm - suspect nasty hack here, why can nesting go negative?]
  }
  if (comment_ender_quoted(from, from_byte, syntax))
     return false; // Comment ender token is in quotes, not a comment ender

  // All tests passed, must be valid comment ender.
  return true;
} 

Now you need to fix up the decrement on the nesting flag. That should be done outside
of the test, as it is logically separate from it.
The Malcolm comments are because Malcolm, who is totally unfamilar with the code, has
dived in and tried to fix it.Naturally they should be replaced.

[toc] | [prev] | [next] | [standalone]


#165949

FromAlan Mackenzie <acm@muc.de>
Date2022-04-26 17:17 +0000
Message-ID<t499fu$13fs$1@news.muc.de>
In reply to#165941
Malcolm McLean <malcolm.arthur.mclean@gmail.com> wrote:
> On Tuesday, 26 April 2022 at 11:34:55 UTC+1, Alan Mackenzie wrote:
>> Tim Rentsch <tr.1...@z991.linuxsc.com> wrote: 
>> > Alan Mackenzie <a...@muc.de> writes: 

>> >> Kaz Kylheku <480-99...@kylheku.com> wrote: 

>> >>> On 2022-04-13, Alan Mackenzie <a...@muc.de> wrote: 

>> > [...] 

>> >>>> Too many parentheses can make C code difficult to read. Difficult 
>> >>>> to read translates to "more bugs". A knowledge of C's precedence 
>> >>>> levels, at least to a moderate degree, can help avoid such bugs. 

>> > I definitely agree with this. 

>> >>> Too much complexity in one expression makes it hard to read. 

>> > I also agree with this. 

>> >>> Other than breaking it up into smaller expression, what can help
>> >>> is to split it into multiple lines and use indentation. 

>> > Sometimes, but rarely. In most cases another choice is better. 

>> >> This is a common attitude, and I'm sure it is wrong a lot of the
>> >> time.  Breaking up a complicated expression _fragments_ it - it
>> >> spreads it over a greater number of source code lines, some of
>> >> which may not be visible on the screen. While each fragment may in
>> >> itself be easier to read, the entire expression has become more
>> >> difficult. 

>> >>> Parenthesized expressions are much more amenable for splitting
>> >>> across lines and indenting than pure infix operator expressions. 

>> > Yuck. Any expression complicated enough to need parentheses _and_
>> > multiple lines _and_ some indication of nesting merits rewriting
>> > into simpler components.

>> That was my point. Such rewriting bloats code, making it more
>> difficult, as a whole, to understand.

>> >> I'm not sure I agree with this, my background being the maintainer
>> >> of Emacs's CC Mode. 

>> >> How about a real world example? In the following (from Emacs's 
>> >> syntax.c): 

>> >> if (code == Sendcomment 
>> >> && SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0) == style 
>> >> && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ? 
>> >> (nesting > 0 && --nesting == 0) : nesting < 0) 
>> >> && !comment_ender_quoted (from, from_byte, syntax)) 

>> >> , which is a moderately complicated example, extra parentheses
>> >> around the operands of the &&s would clutter up the code rather
>> >> than clarifying it. Yet the whole expression being on just five
>> >> lines makes it relatively easy to understand. 

>> > I'm a longtime emacs user, and definitely a fan, but this code 
>> > is horrible, on several different levels.

>> I disagree. The condition being coded is "horrible", so the code
>> cannot be "nice". That condition is testing whether an ostensible
>> comment ender actually ends a comment. There are several things to
>> test, namely, that we're not trying to end a // comment with */, that
>> the comment, if nested (this can happen, for example, in Lisp or
>> Pascal), reaches the outer level of nesting, and that the comment
>> ender isn't quoted.

>> > I agree that adding extra parentheses around the &&s operands would
>> > make things worse, .... 

>> Agreed. 

>> > .... but it's already way below threshold for any reasonable
>> > standard of code review. 

>> This is simply untrue. That piece of code has been reviewed many
>> times, including by me, and presents no particular difficulties in
>> understanding. 

>> I don't think it could be written better.

> /*
>   Does a comment ender token actually end a comment?
>   Params: code - the token (e.g. Sendcomment, Receivecomment [Malcolm ??])
>                   syntax - syntax flags for current comment style (see SYNTAX_FLAGS)
>                   style - current comment style [Malcolm, how does this differ from syntax?]
>                   nesting - nesting level (note can be negative [Malcolm, explain how])
>                   from - start of comment 
>                   from_byte - [Malcolm ???]  
>    Returns: true if the comment ends, else false. 
> */ 
> bool is_comment_ended(int code, unsigned int syntax, unsigned int style, int nesting, char *from, char from_byte)
> {
>     if (code != Sendcomment)
>        return false;  // Not an end comment token
>    if (SYNTAX_FLAGS_COMMENT_STYLE(syntax, 0) != style)
>       return false; // Wrong comment style
>    if (SYNTAX_FLAGS_COMMENT_NESTED(syntax))
>    {
>        if (nesting != 1)
>          return false;  // in a nested comment
>    }
>   else
>   {
>      if (nesting < 0)
>         return false; // [Malcolm - suspect nasty hack here, why can nesting go negative?]
>   }
>   if (comment_ender_quoted(from, from_byte, syntax))
>      return false; // Comment ender token is in quotes, not a comment ender

>   // All tests passed, must be valid comment ender.
>   return true;
> } 

You make my point more eloquently than I could.  ;-)  5 lines have become
20 non-comment lines plus comments, and several more lines will be needed
to handle the decrementation of the variable `nesting'.  These 20 lines
have been fragmented from the context where they formally belonged.  Or,
in plain English, you've got to keep moving backwards and forwards
between this new functiom and the calling point to understand things.

This new function is a bit like the long gentle ramp often seen at the
entrance to public buildings for the benefit of wheelchair users.  It is
less effort to walk up than climbing the stairs, since each step is
gentler, but the total time and energy expended is much more.  Otherwise,
able bodied people would walk up the ramp rather than climbing the
stairs.  In this analogy, the stairs correspond with the five line
original piece of code.

> Now you need to fix up the decrement on the nesting flag. That should
> be done outside of the test, as it is logically separate from it.

Perhaps, perhaps not.  If one construes the 5-line original as "handle a
comment closer", then decrementing the nesting level is an integral part
of it.

> The Malcolm comments are because Malcolm, who is totally unfamilar with
> the code, has dived in and tried to fix it.Naturally they should be
> replaced.

:-)

There're quite a lot of pieces of code like my original citation in the
Emacs C code.  I can't remember there ever being a call to make it less
compact.

-- 
Alan Mackenzie (Nuremberg, Germany).

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web