[Swan-dev] style issue

Andrew Cagney andrew.cagney at gmail.com
Mon Mar 15 21:45:30 UTC 2021


On Mon, 15 Mar 2021 at 16:41, D. Hugh Redelmeier <hugh at mimosa.com> wrote:
>
> This is about a matter of taste.  I'd like to understand why others
> don't agree with me.  I'm not just jumping in to "improve" the code.
>
> I like compact code.  It means that more functionality can be seen at
> once.
>
> That's one reason that I like C better than COBOL (there are many others).
>
> But this can be taken to far: I find APL pretty hard to read.  Maybe it is
> just that I haven't had enough exposure to internalize the set of
> operators.
>
> Anyway, I find this:
>
> bool selector_subnet_in(const ip_selector *lhs, const ip_selector *rhs)
> {
>         ip_subnet lhs_subnet = selector_subnet(*lhs);
>         ip_subnet rhs_subnet = selector_subnet(*rhs);
>         return subnet_in_subnet(lhs_subnet, rhs_subnet);
> }
>
> less readable than:
>
> bool selector_subnet_in(const ip_selector *lhs, const ip_selector *rhs)
> {
>         return subnet_in_subnet(selector_subnet(*lhs), selector_subnet(*rhs));
> }
>
> - shorter (fewer characters, fewer lines)
>
> - fewer variables
>
> - sometimes creating an intermediate variable helps the reader understand
>   what a subexpression means.  I don't see that applies in these cases.
>
> It may be that steppng through the first with gdb is more
> comprehensible than stepping through the second.  But how often are we
> stepping through code with gdb?

We're talking here about:

 * XXX: two hacks to get around .client not containing a proper
 * selector and instead needing to compare just the client's subnet.
 *
 * These are needed by code manipulating end.client because it is
 * serving double time.  It holding either:
 *
 * - the configured client subnet
 * - a connection's shunt

Up until about 10 minutes before this very post, the code had to look like:

  ip_subnet lhs_subnet = selector_subnet(lhs);
  ip_subnet rhs_subnet = selector_subnet(rhs);
  return subnet_in_subnet(&lhs_subnet, &rhs_subnet);

This is because all address functions took pointers and so
intermediate variables were a must!

I've now started changing this and a big motivator is so that I can
write address expressions more naturally, and just like you suggest.

However I'm not about to beautify the code while doing this:
- eliminating variables is what compilers live for
- it makes the diff easier to read
- it makes merging the next change easier (making these changes is
easy, testing is a pita)
(so please don't start beautifying this code).

Ah the irony.

> Here's another example:
>
> bool selector_subnet_is_address(const ip_selector *selector, const
> ip_address *address)
> {
>         if (address_is_unset(address) || selector_is_unset(selector)) {
>                 return false;
>         }
>         ip_subnet subnet = selector_subnet(*selector);
>         return subnet_eq_address(subnet, *address);
> }
>
> This looks simpler to me:
>
> bool selector_subnet_is_address(const ip_selector *selector, const
> ip_address *address)
> {
>         return  !address_is_unset(address) &&
>                 !selector_is_unset(selector) &&
>                 subnet_eq_address(selector_subnet(*selector), *address);
> }
>
> - it is shorter
>
> - there is no control-flow to analyze
>
> - there's no "false" to understand
>
> - a logical conjunction is easier to understand than a disjunction plus
>   a conjunction created by control flow.
>
> - a variable is eliminated
>
> - most of all: you can "read" the meaning of the function directly
>   rather than deriving it through the application of predicate
>   transformers.
>
> - one reason I use an algebraic language rather than assembly code is
>   so that I can write things like this concisely.
>
> What do you think?
> _______________________________________________
> Swan-dev mailing list
> Swan-dev at lists.libreswan.org
> https://lists.libreswan.org/mailman/listinfo/swan-dev


More information about the Swan-dev mailing list