On Tue Nov 19, 2024 at 2:39 AM CET, G. Branden Robinson wrote:
> [...]
> Personally, I have a strong distaste for jamming parentheses up against
> control structure keywords, like `if(` or `switch(`, though I know some
> disciples of old-school Bell Labs code will cling to it unto death.
>
> I also strongly dislike putting a space between a function name and its
> parenthesized argument list.  I believe some people prescribe this
> practice because they're aware that doing so will escape expansion of a
> preprocessor macro, and they "want to be sure they get the function".  I
> think there are multiple things wrong with that view.

Agreed.

> Unless what you're defining _is_ the macro shadowing a function, you
> shouldn't care whether you're expanding a macro or calling a function.
> Encapsulation is good.  If the macro breaks the function interface, the
> macro is buggy and should be fixed, not avoided.

This isn't really about encapsulation. The problem with macros is that
due to the way macro substitution works, arguments may be evaluated
multiple times. An obvious example is:
  #define min(x,y) ((x) < (y) ? (x) : (y))
  int i = 1;
  printf("min = %s\n", min(i++, 3));
which prints:
  min = 2

Not knowing something is a macro can make for mysterious bugs like above.

> [...]
> Rust has a better idea.  If you define a macro, it gets a `!` at the end
> of its name (or maybe more precisely as part of its interpolation
> syntax).  Hard to miss and it even kind of shouts at you to get your
> attention and rouse you from your lull.

I think the best way to avoid issues with macros is to always name
macros in CONSTANT_CASE, because they aren't really interchangeable
with functions. If you can't trust your codebase to follow this rule,
you have a problem and putting a space before the argument list won't
help you.

> > GNU's code style guides tend to be awful.
>
> [...]
> Maybe the only place GNU brace style is really enforced is Emacs,
> because that's where RMS will notice it.

The source code of GNU grep contains stuff like this:
  int inserted = hash_insert_if_absent (pattern_table,
                                        (void *) dst_offset_1, nullptr);

> > > [...] C-like OOP languages [...]
> > 
> > Sounds like an oxymoron to me. Although some OOP constructs are
> > possible in C, they don't come very naturally to the language. Perhaps
> > you meant C++-like? [1]
>
> No, I mean languages that crib their gross syntax from C, such as its
> use of braces for statement grouping, which is a lot of languages.

Oh, I get what you mean.

> All of C, C++, Java, and C# are similar in this respect, and I regard
> them as being in the same family in this sense.
>
> Another tradition is that of Algol/Pascal/Ada.
>
> My favorite criticism of the latter family by advocates of the former is
> that braces are more efficient because they're so much easier to type
> than "begin" and "end".
> [...]

I think that's a strawman. The reason why braces are better is that
they make the code easier to navigate and read because the names of
functions, variables etc. stand out better. The same applies for many
other constructs which C replaced with punctuation. Just look at old
versions of Fortran -- they didn't even use > for greater-than.
(We see remnants of this in shell's test program.)

> > [1] Contrary to what many people think, there is no such thing as
> >     C/C++, because C++ is not a complete superset of C.
>
> The truth value of that statement depends on the domain of discourse.
> C's and C++'s syntaxes much more closely resemble each other than, say,
> either's does *roff.

You could say C#/Java by that logic, but nobody does.

> But I would agree that it's dangerous to assume
> that any non-trivial exhibit of code written in one language that
> happens to compile without diagnostics in the other preserves its
> semantics.  Even some of the trivial cases will change meaning (what's
> the `sizeof` a character literal?).

It's not just that. C++ doesn't support some important C99 constructs,
most notably the struct initialization syntax that allows you to do:
  struct state {
    bool isaccept, isactive;
    int ndisables;
    struct context *ctx;
  };
  struct state st = { .isaccept = 1 };
which works the same as writing:
  // ...
  struct state st;
  st.isaccept = 1;
  st.isactive = 0;
  st.ndisables = 0;
  st.ctx = NULL;

~ onf

Reply via email to