Discussion:
how to make a macro work as a single line if stmt without braces
(too old to reply)
Mark Summerfield
2024-09-21 07:35:49 UTC
Permalink
I have this macro:

#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);

which I use like this:

total++;
if (failed) {
WARN("failed because...");
} else
ok++;

I would prefer to be able to write this instead:

total++;
if (failed)
WARN("failed because...");
else
ok++;

but doing so results in a compiler error:

error: 'else' without a previous 'if'
Lawrence D'Oliveiro
2024-09-21 08:10:51 UTC
Permalink
Post by Mark Summerfield
total++;
if (failed)
WARN("failed because...");
else
ok++;
I wouldn’t, if I were you.
David Brown
2024-09-21 08:47:10 UTC
Permalink
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
total++;
if (failed) {
WARN("failed because...");
} else
ok++;
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
You should get in the habit of being consistent with braces, and being
generous with them. Your future self with thank you.

if (failed) {
WARN("failed because...");
} else {
ok++;
}


The rule here is that you the /only/ time you allow yourself to omit the
braces is if you have a very simple "if" that has no "else", is small
enough to fit entirely on a single line, and the statement could not
possibly be misinterpreted, use a macro, or have any other non-obvious
behaviour.

Thus :

if (failed) return -1; // Early exit

or

if (!failed) ok++;

Otherwise, put in all the braces.

This also keeps your indentation consistent - open braces are only at
the end of a line, and the next line starts an indented block. Close
braces are only ever the first non-indent character in a line, and you
un-indent on the close brace.

(It's common to put the opening brace of a function at the start of its
own line, and braces for struct or array initialisation can be freer.)

do, while and for loops always use braces.



There are a few other variant styles that are also consistent and clear,
but usually they end up unnecessarily spread out. (Opinions will vary
about that.) But getting good habits here from early one will make your
code much clearer, greatly reduce the risk of blocking errors, and be a
significant boon for code maintenance and the use of version control
systems.
Andrey Tarasevich
2024-09-21 19:27:03 UTC
Permalink
Post by David Brown
You should get in the habit of being consistent with braces, and being
generous with them.  Your future self with thank you.
if (failed) {
    WARN("failed because...");
} else {
    ok++;
}
Nope. There's absolutely no reason to overuse braces.

And don't use "Egyptian" braces. The latter is actually an ill-begotten
attempt to remedy the damage from the former. Just stop overusing
braces, and there'll be no need for the remedy. Easy.

This is the proper formatting style with braces

if (failed)
{
...
}
else
{
...
}

The vertical spacing introduced by the `{` line provides separation
between condition and the branch, which makes your code much more
readable. It is also a very good location for a comment, if you decide
to include one. Your future self with thank you.
Post by David Brown
... is small
enough to fit entirely on a single line, and the statement could not
possibly be misinterpreted, use a macro, or have any other non-obvious
behaviour.
    if (failed) return -1;        // Early exit
or
    if (!failed) ok++;
Otherwise, put in all the braces.
Nope. Do not ever write single-line `if` statements. This is a major
impediment to step-by-step debugging.
--
Best regards,
Andrey
Bart
2024-09-21 20:11:21 UTC
Permalink
Post by Andrey Tarasevich
Post by David Brown
You should get in the habit of being consistent with braces, and being
generous with them.  Your future self with thank you.
if (failed) {
     WARN("failed because...");
} else {
     ok++;
}
Nope. There's absolutely no reason to overuse braces.
And don't use "Egyptian" braces. The latter is actually an ill-begotten
attempt to remedy the damage from the former. Just stop overusing
braces, and there'll be no need for the remedy. Easy.
This is the proper formatting style with braces
  if (failed)
  {
    ...
  }
  else
  {
    ...
  }
The vertical spacing introduced by the `{` line provides separation
between condition and the branch,
Have a look at the middle of that example:

} else {

Here the braces serve no purpose; you already have 'else' separating the
two branches to which you can add extra vertical space if you like.

This is not just because of braces, you get the same thing with:

end else begin

Both are symptoms of the idea that any branch can only have a single
statement, and if you need more, than you need a compound statement
using {s1; s2; s3;} (unless you're Tim then you use s1, s2, s3 which may
or may not work and is probably the worst of all).

Since this is C, then if braces are to be mandatory, then at least allow
people to write their code a little more compactly if they wish. In a
language that allows proper statement sequences, you wouldn't commonly
see this:

if failed then

s1

else

s2

...

But this exactly how you are suggesting C should be written, when
looking purely at the content: 50% blank lines.

It looks ridiculous and those statements look very lonely!
Opus
2024-09-21 20:39:10 UTC
Permalink
Post by Andrey Tarasevich
Nope. There's absolutely no reason to overuse braces.
And don't use "Egyptian" braces. The latter is actually an ill-begotten
attempt to remedy the damage from the former. Just stop overusing
braces, and there'll be no need for the remedy. Easy.
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides separation
between condition and the branch, which makes your code much more
readable. It is also a very good location for a comment, if you decide
to include one. Your future self with thank you.
I agree with that, but you realize you are kinda fighting
"establishment" here. What you call "egyptian" braces is the so-called
"TBS" which has infected the "default style" of approximately all
programming languages that use braces. People use that almost
religiously and the only rationale is to save space. Might have made
sense 40 years ago when screen estate was a lot smaller, but these days,
it's just madness. It's a lot less readable. The details are also odd:
they seem to despise having an opening brace alone on a line, but they
don't mind the closing brace to be.

This is even worse: } else {
starting a line with a closing symbol and ending it with an opening
symbol, really?

As to overuse, my own style and guideline is this: if both 'then' and
'else' blocks are single statements, don't use braces.

If any of these blocks have more than one statement, use braces for both
to make it look consistent. Mixed braces in if/else do look terrible
IMHO (and the lack of consistency always hinders readablity), like this:

if (something)
dothis();
else
{
dothat();
andalsothat();
}

Just avoid it.

I've seen that code style guideline in various environments, so this
isn't just my own either.

Now the rationale for always using braces even for single statements at
least makes some sense. Usually, it's for avoiding the case when a
developer will add statements to a if or else block, forget to add
braces to enclose it, and so that becomes a bug (which can't be easily
trapped by compilers unless it's between a if and else. Some
compilers/static analyzers, if you at least used proper indenting, will
spot the indenting and lack of braces and will warn you about a
potential mistake though.
Keith Thompson
2024-09-21 21:54:52 UTC
Permalink
Post by Andrey Tarasevich
Post by David Brown
You should get in the habit of being consistent with braces, and
being generous with them.  Your future self with thank you.
if (failed) {
    WARN("failed because...");
} else {
    ok++;
}
Nope. There's absolutely no reason to overuse braces.
Plenty of C programmers, myself included, disagree with this.

One reason to "overuse" braces is that you can easily add another
statement. If you write:

if (failed)
    WARN("failed because...");
else
    ok++;

and later decide you need two statements in the else clause, you then
need to add braces. If they're already there, you don't.
Post by Andrey Tarasevich
And don't use "Egyptian" braces. The latter is actually an
ill-begotten attempt to remedy the damage from the former. Just stop
overusing braces, and there'll be no need for the remedy. Easy.
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
Again, many, perhaps most, C programmers will disagree with this.

What you call "Egyptian" braces is the style used by the creators of the
language and in a *lot* of open source software. Even if you don't like
the style, you'll need to deal with it.

I have my own fairly strong preferences about brace placement, but the
most important rule is to follow the conventions of the code I'm working
on.

[...]
Post by Andrey Tarasevich
Post by David Brown
    if (failed) return -1;        // Early exit
or
    if (!failed) ok++;
Otherwise, put in all the braces.
Nope. Do not ever write single-line `if` statements. This is a major
impediment to step-by-step debugging.
I've rarely run into that problem. When I have, it's been easy enough
to temporarily modify the code.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Andrey Tarasevich
2024-09-22 03:05:51 UTC
Permalink
Post by Keith Thompson
One reason to "overuse" braces is that you can easily add another
if (failed)
    WARN("failed because...");
else
    ok++;
and later decide you need two statements in the else clause, you then
need to add braces. If they're already there, you don't.
Adding braces in this situation is _incomparably_ easier than splitting
an annoying single-line `if` statement into multiple lines, discovered
during an interactive debugging session. Which is something you yourself
described as "easy enough" below.
Post by Keith Thompson
What you call "Egyptian" braces is the style used by the creators of the
language
Firstly, this is style. Being a "creator of the language" does not make
one an authority on code formatting style.

Secondly, most people pick up "the style used by the creators of the
language" from the code samples used in the 2nd edition of K&R book.
And, as we know, "the creators of the language" went a little lazy here.
The samples were considered of "low importance" and fell victim to the
tightening publishing schedules in front of the looming "threat" of the
upcoming ANSI standard. The code samples were never properly updated to
match the style and spirit of modern C.

This is BTW, the reason we have to deal with that pesky and atrocious
manner to cast the result of `malloc` - another practice erroneously
believed to be "the style used by the creators of the language".
Post by Keith Thompson
and in a *lot* of open source software. Even if you don't like
the style, you'll need to deal with it.
I have my own fairly strong preferences about brace placement, but the
most important rule is to follow the conventions of the code I'm working
on.
Certainly. It is not a good practice to force your own style onto
someone else's code or an already existing code. Still, in most
reasonably organized professional development environments personal
preferences are normally welcomed with certain granularity. It is
usually organized on "per translation unit" basis.
--
Best regards,
Andrey
Keith Thompson
2024-09-22 04:33:28 UTC
Permalink
Post by Andrey Tarasevich
Post by Keith Thompson
One reason to "overuse" braces is that you can easily add another
if (failed)
    WARN("failed because...");
else
    ok++;
and later decide you need two statements in the else clause, you then
need to add braces. If they're already there, you don't.
Adding braces in this situation is _incomparably_ easier than
splitting an annoying single-line `if` statement into multiple lines,
discovered during an interactive debugging session. Which is something
you yourself described as "easy enough" below.
Perhaps I don't use interactive debuggers as much as other programmers
do, but I certainly haven't found it terribly difficult to temporarily
reformat code as needed (not that I've run into that particular issue
very often). I'm likely to be modifying and rebuilding the software
anyway.
Post by Andrey Tarasevich
Post by Keith Thompson
What you call "Egyptian" braces is the style used by the creators of the
language
Firstly, this is style. Being a "creator of the language" does not
make one an authority on code formatting style.
True.
Post by Andrey Tarasevich
Secondly, most people pick up "the style used by the creators of the
language" from the code samples used in the 2nd edition of K&R
book. And, as we know, "the creators of the language" went a little
lazy here. The samples were considered of "low importance" and fell
victim to the tightening publishing schedules in front of the looming
"threat" of the upcoming ANSI standard. The code samples were never
properly updated to match the style and spirit of modern C.
You seem to be asserting that K&R-style brace placement goes against
"the style and spirit of modern C". In my opinion and experience, it
absolutely does not.

You prefer braces on their own lines. I prefer to put opening braces at
the end of the line. Neither of us is objectively right or wrong.
Post by Andrey Tarasevich
This is BTW, the reason we have to deal with that pesky and atrocious
manner to cast the result of `malloc` - another practice erroneously
believed to be "the style used by the creators of the language".
Post by Keith Thompson
and in a *lot* of open source software. Even if you don't like
the style, you'll need to deal with it.
I have my own fairly strong preferences about brace placement, but the
most important rule is to follow the conventions of the code I'm working
on.
Certainly. It is not a good practice to force your own style onto
someone else's code or an already existing code. Still, in most
reasonably organized professional development environments personal
preferences are normally welcomed with certain granularity. It is
usually organized on "per translation unit" basis.
That's not my experience at all. In some environments, there's a
project-wide written coding standard (which may or may not be strictly
followed). In others, the style is (ideally) consistent at least across
each project or subproject.

I suppose I could deal with a project where each translation unit has
its own style, but thankfully I've never had to.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
David Brown
2024-09-22 12:15:28 UTC
Permalink
Post by Andrey Tarasevich
Post by Keith Thompson
One reason to "overuse" braces is that you can easily add another
     if (failed)
          WARN("failed because...");
     else
          ok++;
and later decide you need two statements in the else clause, you then
need to add braces.  If they're already there, you don't.
Adding braces in this situation is _incomparably_ easier than splitting
an annoying single-line `if` statement into multiple lines, discovered
during an interactive debugging session. Which is something you yourself
described as "easy enough" below.
I don't think "incomparably" is the word you are looking for -
especially while making a comparison!

Changes can always be made to code, and none of this is a particular
challenge to do.
Post by Andrey Tarasevich
Post by Keith Thompson
What you call "Egyptian" braces is the style used by the creators of the
language
Firstly, this is style. Being a "creator of the language" does not make
one an authority on code formatting style.
Agreed.
Post by Andrey Tarasevich
Secondly, most people pick up "the style used by the creators of the
language" from the code samples used in the 2nd edition of K&R book.
And, as we know, "the creators of the language" went a little lazy here.
The samples were considered of "low importance" and fell victim to the
tightening publishing schedules in front of the looming "threat" of the
upcoming ANSI standard. The code samples were never properly updated to
match the style and spirit of modern C.
I can't speak for anyone else, but it is certainly not why I use this
style. I have tried a few styles, I have seen many more, and it was a
conscious decision about what I think makes code clearer to read and has
the minimal risk of errors or misunderstandings.
Post by Andrey Tarasevich
This is BTW, the reason we have to deal with that pesky and atrocious
manner to cast the result of `malloc` - another practice erroneously
believed to be "the style used by the creators of the language".
There are plenty of design decisions in C that some people will think
were a good idea, and others think are a bad idea. Let's not go there!
Post by Andrey Tarasevich
Post by Keith Thompson
and in a *lot* of open source software.  Even if you don't like
the style, you'll need to deal with it.
I have my own fairly strong preferences about brace placement, but the
most important rule is to follow the conventions of the code I'm working
on.
Agreed.

There's nothing worse than a git/subversion/whatever checkin when
someone has changed the entire file to move around some braces or
convert between their preferences of tabs or spaces.[1]
Post by Andrey Tarasevich
Certainly. It is not a good practice to force your own style onto
someone else's code or an already existing code. Still, in most
reasonably organized professional development environments personal
preferences are normally welcomed with certain granularity. It is
usually organized on "per translation unit" basis.
Practices vary somewhat. And while there's a fair variety of styles
that can be seen as reasonable enough, it sometimes happens that the new
person in a team has such a terrible style that they are forced to change.



[1] Except, of course, a paper-cut. It's a well-established fact that
there is nothing worse than a paper-cut!
Tim Rentsch
2024-09-27 10:38:27 UTC
Permalink
[...]
Post by Keith Thompson
What you call "Egyptian" braces is the style used by the creators
of the language
Firstly, this is style. Being a "creator of the language" does not
make one an authority on code formatting style.
Secondly, most people pick up "the style used by the creators of
the language" from the code samples used in the 2nd edition of K&R
book. And, as we know, "the creators of the language" went a
little lazy here. The samples were considered of "low importance"
and fell victim to the tightening publishing schedules in front of
the looming "threat" of the upcoming ANSI standard. The code
samples were never properly updated to match the style and spirit
of modern C.
Your reasoning is rife with errors of logic and facts not in
evidence.
David Brown
2024-09-22 11:59:53 UTC
Permalink
Post by Andrey Tarasevich
Post by David Brown
You should get in the habit of being consistent with braces, and being
generous with them.  Your future self with thank you.
To be clear here - many people have strong opinions about this topic,
and there is no good evidence for claiming that one style is "better"
than other styles. Different styles can have their pros and cons, and
people will give different weightings to those pros and cons when
choosing a style.

So I fully respect your opinion here. But you are still wrong :-)
Post by Andrey Tarasevich
Post by David Brown
if (failed) {
     WARN("failed because...");
} else {
     ok++;
}
Nope. There's absolutely no reason to overuse braces.
I am not suggesting overuse of braces. I am suggesting /good/ use of them.

<https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html>

That's perhaps the most famous example of the havoc caused by omitting
useful braces.

Consistency and clarity is important. So is maintainability. Suppose,
for example, you want to add a line "attempts++;" alongside the "ok++;"
line. When the braces are there, the change is exactly that - add the
new line you want. Without the original braces, you are now making
changes to the structural syntax of the code as well when you add in
original braces - or you are making a mistake in the code.
Post by Andrey Tarasevich
And don't use "Egyptian" braces. The latter is actually an ill-begotten
attempt to remedy the damage from the former. Just stop overusing
braces, and there'll be no need for the remedy. Easy.
This is the proper formatting style with braces
  if (failed)
  {
    ...
  }
  else
  {
    ...
  }
The vertical spacing introduced by the `{` line provides separation
between condition and the branch, which makes your code much more
readable. It is also a very good location for a comment, if you decide
to include one. Your future self with thank you.
No, it makes code longer and more tedious to read, and wastes
significant vertical space so that you can see less code at a time. It
leads people to think that it is a good idea to skip braces when they
can. Put braces in a sensible place and there is no incentive to skip them.

One important point for readability is to keep the conditionals
relatively short so that the open brace is not far to the right - an
overly complex expression is usually a bad idea anyway.
Post by Andrey Tarasevich
Post by David Brown
...  is small
enough to fit entirely on a single line, and the statement could not
possibly be misinterpreted, use a macro, or have any other non-obvious
behaviour.
     if (failed) return -1;        // Early exit
or
     if (!failed) ok++;
Otherwise, put in all the braces.
Nope. Do not ever write single-line `if` statements. This is a major
impediment to step-by-step debugging.
That is indeed true. Sometimes when you have code that you need to
single-step or debug carefully, you need to express it a little
differently or make syntactic changes to help. (A common one is to mark
some of the local variables as "volatile".)

I think it is reasonable to have such short one-line conditionals in
simple cases, but it is certainly not a requirement - filling them out
with the braces is fine too.
Kaz Kylheku
2024-09-22 15:11:56 UTC
Permalink
Post by David Brown
I am not suggesting overuse of braces. I am suggesting /good/ use of them.
<https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html>
That's perhaps the most famous example of the havoc caused by omitting
useful braces.
Consistency and clarity is important. So is maintainability. Suppose,
for example, you want to add a line "attempts++;" alongside the "ok++;"
line. When the braces are there, the change is exactly that - add the
new line you want. Without the original braces, you are now making
changes to the structural syntax of the code as well when you add in
original braces - or you are making a mistake in the code.
My super advanced text editor from the future isn't letting me do that:

if (failed)
WARN("failed because...");
else
ok++;
attempts++; // automatic deindent

When I add a line after ok++, it deindents it to be at the same
indentation level as the if, before letting me type any content into it.

OK, I lied about the super advanced from the future. It's just Vim.

Also GCC has been able to diagnose misleading indentation for some
years now.

Between those two, there is nothing to worry about; just concentrate on
whether it looks prettier without the braces or with.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Bart
2024-09-22 15:56:47 UTC
Permalink
Post by Mark Summerfield
Post by David Brown
I am not suggesting overuse of braces. I am suggesting /good/ use of them.
<https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html>
That's perhaps the most famous example of the havoc caused by omitting
useful braces.
Consistency and clarity is important. So is maintainability. Suppose,
for example, you want to add a line "attempts++;" alongside the "ok++;"
line. When the braces are there, the change is exactly that - add the
new line you want. Without the original braces, you are now making
changes to the structural syntax of the code as well when you add in
original braces - or you are making a mistake in the code.
if (failed)
WARN("failed because...");
else
ok++;
attempts++; // automatic deindent
When I add a line after ok++, it deindents it to be at the same
indentation level as the if, before letting me type any content into it.
OK, I lied about the super advanced from the future. It's just Vim.
Also GCC has been able to diagnose misleading indentation for some
years now.
Between those two, there is nothing to worry about; just concentrate on
whether it looks prettier without the braces or with.
So, everyone has to write code exactly to the C standard.

But when it comes to more practical matters, it's OK to depend on the
arbitrary characteristics and abilities of whichever one of 1001
different text editors we happen to be using.

Or we have to use a specific compiler with a specific set of options.
Post by Mark Summerfield
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn it
on? Since -Wall -Wpedantic -Wextra doesn't report it.

It is a failure in the design of the language. You can't really depend
on ad hoc features of the tools you use to create and compile source code.

At least guidelines can be used such as always using braces, then errors
can occur less often.

(I've been bitten by this endless times when trying to add debugging
statements to existing code. If that code consistently used braces, then
it wouldn't happen.)
Michael S
2024-09-22 16:27:26 UTC
Permalink
On Sun, 22 Sep 2024 16:56:47 +0100
Post by Bart
Post by Mark Summerfield
Post by David Brown
I am not suggesting overuse of braces. I am suggesting /good/ use of them.
<https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html>
That's perhaps the most famous example of the havoc caused by
omitting useful braces.
Consistency and clarity is important. So is maintainability.
Suppose, for example, you want to add a line "attempts++;"
alongside the "ok++;" line. When the braces are there, the change
is exactly that - add the new line you want. Without the original
braces, you are now making changes to the structural syntax of the
code as well when you add in original braces - or you are making a
mistake in the code.
if (failed)
WARN("failed because...");
else
ok++;
attempts++; // automatic deindent
When I add a line after ok++, it deindents it to be at the same
indentation level as the if, before letting me type any content into it.
OK, I lied about the super advanced from the future. It's just Vim.
Also GCC has been able to diagnose misleading indentation for some
years now.
Between those two, there is nothing to worry about; just
concentrate on whether it looks prettier without the braces or with.
So, everyone has to write code exactly to the C standard.
But when it comes to more practical matters, it's OK to depend on the
arbitrary characteristics and abilities of whichever one of 1001
different text editors we happen to be using.
Or we have to use a specific compiler with a specific set of options.
Post by Mark Summerfield
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn
it on? Since -Wall -Wpedantic -Wextra doesn't report it.
My gcc warns just fine.

void bar(int);
int foo(int x) {
if (x)
bar(x);
x -= 1;
return x;
}

gcc -c -Wall foo.c

foo.c: In function 'foo':
foo.c:3:3: warning: this 'if' clause does not guard...
[-Wmisleading-indentation] 3 | if (x)
| ^~
foo.c:5:5: note: ...this statement, but the latter is misleadingly
indented as if it were guarded by the 'if'
5 | x -= 1;
| ^
Post by Bart
It is a failure in the design of the language. You can't really
depend on ad hoc features of the tools you use to create and compile
source code.
At least guidelines can be used such as always using braces, then
errors can occur less often.
(I've been bitten by this endless times when trying to add debugging
statements to existing code. If that code consistently used braces,
then it wouldn't happen.)
I wonder why I was not bitten by that more than, may be, 5 times in
30+ years. Probably, I am doing something wrong.
Bart
2024-09-22 16:47:23 UTC
Permalink
Post by Michael S
On Sun, 22 Sep 2024 16:56:47 +0100
Post by Bart
Post by Mark Summerfield
Post by David Brown
I am not suggesting overuse of braces. I am suggesting /good/ use of them.
<https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html>
That's perhaps the most famous example of the havoc caused by
omitting useful braces.
Consistency and clarity is important. So is maintainability.
Suppose, for example, you want to add a line "attempts++;"
alongside the "ok++;" line. When the braces are there, the change
is exactly that - add the new line you want. Without the original
braces, you are now making changes to the structural syntax of the
code as well when you add in original braces - or you are making a
mistake in the code.
if (failed)
WARN("failed because...");
else
ok++;
attempts++; // automatic deindent
When I add a line after ok++, it deindents it to be at the same
indentation level as the if, before letting me type any content into it.
OK, I lied about the super advanced from the future. It's just Vim.
Also GCC has been able to diagnose misleading indentation for some
years now.
Between those two, there is nothing to worry about; just
concentrate on whether it looks prettier without the braces or with.
So, everyone has to write code exactly to the C standard.
But when it comes to more practical matters, it's OK to depend on the
arbitrary characteristics and abilities of whichever one of 1001
different text editors we happen to be using.
Or we have to use a specific compiler with a specific set of options.
Post by Mark Summerfield
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn
it on? Since -Wall -Wpedantic -Wextra doesn't report it.
My gcc warns just fine.
void bar(int);
int foo(int x) {
if (x)
bar(x);
x -= 1;
return x;
}
gcc -c -Wall foo.c
foo.c:3:3: warning: this 'if' clause does not guard...
[-Wmisleading-indentation] 3 | if (x)
| ^~
foo.c:5:5: note: ...this statement, but the latter is misleadingly
indented as if it were guarded by the 'if'
5 | x -= 1;
| ^
That doesn't pick up a program that in my editor looks like this:

------------------------
int main(void){
total++;
if (failed)
WARN("failed because...");
else
ok++;
failed=0;
}
------------------------

However, the first two indents use four spaces, but the third uses a
hard tab that my editor shows as four spaces, but if I print it out to
the console, it shows this:

------------------------
int main(void){
total++;
if (failed)
WARN("failed because...");
else
ok++;
failed=0;
}
------------------------

That odd indentation is not picked up either. But it will say something
if all indents used spaces or used hard tabs.

If the language has explicit block delimiters (either mandatory braces,
or endings like 'end'), then the problem simply wouldn't arise. That
'failed=0' line would either be before the delimiter or after it. The
original example would look something like this:


------------------------
if (failed) {
WARN("failed because...");
} else {
ok++;
}
failed=0;
------------------------
That line is still mis-indented, but is now less likely to be taken to
be part of that 'else' block.
Post by Michael S
Post by Bart
It is a failure in the design of the language. You can't really
depend on ad hoc features of the tools you use to create and compile
source code.
At least guidelines can be used such as always using braces, then
errors can occur less often.
(I've been bitten by this endless times when trying to add debugging
statements to existing code. If that code consistently used braces,
then it wouldn't happen.)
I wonder why I was not bitten by that more than, may be, 5 times in
30+ years. Probably, I am doing something wrong.
How you tried to debug other people's code via adding printf statements
at strategic points?
Tim Rentsch
2024-09-24 14:36:39 UTC
Permalink
Post by Michael S
On Sun, 22 Sep 2024 16:56:47 +0100
Post by Bart
Post by Mark Summerfield
Post by David Brown
I am not suggesting overuse of braces. I am suggesting /good/ use of them.
<https://www.synopsys.com/blogs/software-security/
understanding-apple-goto-fail-vulnerability-2.html>
That's perhaps the most famous example of the havoc caused by
omitting useful braces.
Consistency and clarity is important. So is maintainability.
Suppose, for example, you want to add a line "attempts++;"
alongside the "ok++;" line. When the braces are there, the change
is exactly that - add the new line you want. Without the original
braces, you are now making changes to the structural syntax of the
code as well when you add in original braces - or you are making a
mistake in the code.
if (failed)
WARN("failed because...");
else
ok++;
attempts++; // automatic deindent
When I add a line after ok++, it deindents it to be at the same
indentation level as the if, before letting me type any content into it.
OK, I lied about the super advanced from the future. It's just
Vim.
Also GCC has been able to diagnose misleading indentation for some
years now.
Between those two, there is nothing to worry about; just
concentrate on whether it looks prettier without the braces or with.
So, everyone has to write code exactly to the C standard.
But when it comes to more practical matters, it's OK to depend on
the arbitrary characteristics and abilities of whichever one of
1001 different text editors we happen to be using.
Or we have to use a specific compiler with a specific set of
options.
Post by Mark Summerfield
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you
turn it on? Since -Wall -Wpedantic -Wextra doesn't report it.
My gcc warns just fine.
void bar(int);
int foo(int x) {
if (x)
bar(x);
x -= 1;
return x;
}
gcc -c -Wall foo.c
foo.c:3:3: warning: this 'if' clause does not guard...
[-Wmisleading-indentation] 3 | if (x)
| ^~
foo.c:5:5: note: ...this statement, but the latter is misleadingly
indented as if it were guarded by the 'if'
5 | x -= 1;
| ^
Post by Bart
It is a failure in the design of the language. You can't really
depend on ad hoc features of the tools you use to create and
compile source code.
At least guidelines can be used such as always using braces, then
errors can occur less often.
(I've been bitten by this endless times when trying to add
debugging statements to existing code. If that code consistently
used braces, then it wouldn't happen.)
I wonder why I was not bitten by that more than, may be, 5 times
in 30+ years. Probably, I am doing something wrong.
My long-standing habit is to write this

if(x) bar(x);

or this

if(x){
bar(x);
}

but never this

if(x)
bar(x);

The reason for this habit is that many years ago I got bitten by
trying to add a line in the last case. The habit subsequently
adopted has proven very effective at eliminating such errors.

The idea of changing the language to always require braces is
unnecessary and wasteful (besides being a non-starter for purely
practical reasons).
Andrey Tarasevich
2024-09-24 14:52:02 UTC
Permalink
Post by Tim Rentsch
My long-standing habit is to write this
if(x) bar(x);
or this
if(x){
bar(x);
}
but never this
if(x)
bar(x);
The reason for this habit is that many years ago I got bitten by
trying to add a line in the last case. The habit subsequently
adopted has proven very effective at eliminating such errors.
It is just weird.

This is no different from insisting in using "Yoda conditions", claiming
that "many years ago I was bitten by an accidental = in place of ==". In
reality we all know that regardless of how many scary stories someone
might tell about dangers of accidental assignment in place of
comparison, it just does not happen. There's no such issue. People just
don't make this mistake.

The same applies to

if(x)
bar(x);

This is the right thing to do. It is the most readable and elegant way
to write a simple `if`. And the dreaded "one day you will add a line and
suffer" just doesn't happen. There's no such issue. People just don't
make this mistake.
--
Best regards,
Andrey
David Brown
2024-09-24 15:24:32 UTC
Permalink
Post by Andrey Tarasevich
Post by Tim Rentsch
My long-standing habit is to write this
    if(x)  bar(x);
or this
    if(x){
       bar(x);
    }
but never this
    if(x)
       bar(x);
The reason for this habit is that many years ago I got bitten by
trying to add a line in the last case.  The habit subsequently
adopted has proven very effective at eliminating such errors.
It is just weird.
This is no different from insisting in using "Yoda conditions", claiming
that "many years ago I was bitten by an accidental = in place of ==". In
reality we all know that regardless of how many scary stories someone
might tell about dangers of accidental assignment in place of
comparison, it just does not happen. There's no such issue. People just
don't make this mistake.
They do.

You might not do so, but other people do. Not often, but still too often.

(I don't think Yoda conditions are the answer here - automatic checking
from tools is simple enough.)
Post by Andrey Tarasevich
The same applies to
  if(x)
    bar(x);
This is the right thing to do. It is the most readable and elegant way
to write a simple `if`. And the dreaded "one day you will add a line and
suffer" just doesn't happen. There's no such issue. People just don't
make this mistake.
Again, people do.

I gave you a link earlier to a hugely costly example of this mistake,
made by very experienced C programmers.

But I am confident that Tim, and others (like me) who use a similar
style, are almost entirely immune to this particular mistake.

Now, if there were a good way to automatically detect mixups between &
and &&, | and ||, then we'd be rid of a number of these kinds of errors
in C coding.
Bart
2024-09-24 16:22:25 UTC
Permalink
Post by Andrey Tarasevich
Post by Tim Rentsch
My long-standing habit is to write this
    if(x)  bar(x);
or this
    if(x){
       bar(x);
    }
but never this
    if(x)
       bar(x);
The reason for this habit is that many years ago I got bitten by
trying to add a line in the last case.  The habit subsequently
adopted has proven very effective at eliminating such errors.
It is just weird.
This is no different from insisting in using "Yoda conditions", claiming
that "many years ago I was bitten by an accidental = in place of ==". In
reality we all know that regardless of how many scary stories someone
might tell about dangers of accidental assignment in place of
comparison, it just does not happen. There's no such issue. People just
don't make this mistake.
The same applies to
  if(x)
    bar(x);
This is the right thing to do. It is the most readable and elegant way
to write a simple `if`.
Well, it is the ONLY way C provides to write the branches of an
if-statement. Each only takes a single statement.

For more than one statement in a branch, they have to be enclosed in a
compound statement with braces.
Post by Andrey Tarasevich
And the dreaded "one day you will add a line and
suffer" just doesn't happen. There's no such issue.
No, this must happen ALL THE TIME. That is, you write one statement,
then decide you need more than one. Or you start with 3 statements and
get rid of two of them.

So, what happens: is there are some of sort dance where you add {,}
braces when N increases beyond 1, and remove them when N reaches 1 again?

What happens when N changes from 1 to 0 (eg. a statement is temporarily
commented out? Without braces, this will causes problems (unless somehow
you have its closing";" on its own line), because then the following
statement is taken to be the branch, with an additional problem if
'else' actually follows.

I haven't even got to the bit where you might make a mistake that is not
picked up by a compiler.

It's a just one big palaver that can solved easily by always using a
compound statement which has opening and closing braces. Within such a
statement, N can vary between 0, 1 and any other number, any of
combination can be commented out, without needing to take any special
action.

It can also happen that when starting to write a branch, you don't know
what N is going to be, or maybe the statements will be filled in later.
Here it is useful to have {} as a placeholder for those statements.
Post by Andrey Tarasevich
People just don't
make this mistake.
And there is that too. Maybe YOU don't make it, in the same way that you
probably know all the binary operator precedences by heart and never get
them wrong. Well, not everyone is perfect.
Keith Thompson
2024-09-24 19:28:57 UTC
Permalink
[...]
Post by Bart
Post by Andrey Tarasevich
The same applies to
  if(x)
    bar(x);
This is the right thing to do. It is the most readable and elegant
way to write a simple `if`.
Well, it is the ONLY way C provides to write the branches of an
if-statement. Each only takes a single statement.
You misunderstood. Andrey was saying that
if(x)
bar(x);
is right and
if(x) bar(x);
is wrong. Of course both are legal; Andrey is arguing that nobody
should ever use the second form.

[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Tim Rentsch
2024-09-27 08:43:34 UTC
Permalink
Post by Andrey Tarasevich
Post by Tim Rentsch
My long-standing habit is to write this
if(x) bar(x);
or this
if(x){
bar(x);
}
but never this
if(x)
bar(x);
The reason for this habit is that many years ago I got bitten by
trying to add a line in the last case. The habit subsequently
adopted has proven very effective at eliminating such errors.
It is just weird.
This is no different from insisting in using "Yoda conditions",
claiming that "many years ago I was bitten by an accidental =
in place of ==".
Don't be silly, of course they are different. There is nothing
artificial about surrounding controlled statements with braces.
And writing braceless single-line if()s in cases where there
is only a single controlled statement is something I was already
doing - I didn't adopt it as a reaction to something that
happened with multi-line if()s.
Post by Andrey Tarasevich
In reality we all know that regardless of how many scary
stories someone might tell about dangers of accidental
assignment in place of comparison, it just does not happen.
There's no such issue. People just don't make this mistake.
Your view is contradicted by objective reality.
Post by Andrey Tarasevich
The same applies to
if(x)
bar(x);
This is the right thing to do. It is the most readable and
elegant way to write a simple `if`.
I think you need to learn the difference between a statement
of opinion and a statement of fact.
Post by Andrey Tarasevich
And the dreaded "one day you will add a line and suffer" just
doesn't happen. There's no such issue. People just don't make
this mistake.
Making a false statement twice doesn't make it true.
Bart
2024-09-24 16:35:28 UTC
Permalink
Post by Tim Rentsch
The idea of changing the language to always require braces is
unnecessary and wasteful (besides being a non-starter for purely
practical reasons).
Well, practically it is not difficult.

I started modifying my compiler to do it, but found I already had that
option, which was a hard-coded value in the source. It took a minute to
reenable it. Support for it requires 2-3 lines of code.

However, that makes an exception for if-else chains, so that you can
still write:

if (c1) {} else if (c2) {} else if (c3) {}

instead of needing:

if (c1) {} else {if (c2) {} else {if (c3) {}}}

(Maybe the language needs a construct like 'elif', as is used in
languages like, say, C's own preprocessor! HTH did that end up with the
sensible syntax while the main language was stuck with the rubbish one?)

BTW with mandatory braces enforced, my generated-C applications still
build with no problems. Because generated code always uses braces. There
is no point in leaving them out, other than perhaps ending up with 0.5%
smaller output.
Keith Thompson
2024-09-24 19:30:38 UTC
Permalink
Post by Bart
Post by Tim Rentsch
The idea of changing the language to always require braces is
unnecessary and wasteful (besides being a non-starter for purely
practical reasons).
Well, practically it is not difficult.
Changing a compiler to require compound statements would not be
difficult. Changing the language in that way would be completely
impractical, because it would break existing code.

[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Bart
2024-09-24 19:42:55 UTC
Permalink
Post by Keith Thompson
Post by Bart
Post by Tim Rentsch
The idea of changing the language to always require braces is
unnecessary and wasteful (besides being a non-starter for purely
practical reasons).
Well, practically it is not difficult.
Changing a compiler to require compound statements would not be
difficult. Changing the language in that way would be completely
impractical, because it would break existing code.
But not new code that uses compound statements, which is will still be
compatible with compilers that don't enforce it.

And as I said, it doesn't break my generated code, and the first
substantial manually written program I tried worked too.

Adding such an option, if it doesn't already exist, would be trivial.
Kaz Kylheku
2024-09-24 19:59:30 UTC
Permalink
Post by Bart
(Maybe the language needs a construct like 'elif', as is used in
The language doesn't need such a construct in order for a compiler
to implement it internally.

You just have to treat the token sequence else if as a supertoken.

Doing it at the grammar level may require two symbols of lookahead,
which is a a problem for off-the-shelf parser generation tooling based
on LALR(1) and whatnot.

A possible trick is to handle it at the lexical level. The pattern
else{WSP}if can be recognized as a single token, assigned its own
enumeration symbol. {WSP} is arbitrary whitespace. (We assume
comments have been stripped by a lower preprocessing phase.)
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Bart
2024-09-24 20:12:28 UTC
Permalink
Post by Kaz Kylheku
Post by Bart
(Maybe the language needs a construct like 'elif', as is used in
The language doesn't need such a construct in order for a compiler
to implement it internally.
You just have to treat the token sequence else if as a supertoken.
Doing it at the grammar level may require two symbols of lookahead,
which is a a problem for off-the-shelf parser generation tooling based
on LALR(1) and whatnot.
That sounds as much of a hack as making a special case for 'else if' so
that it doesn't need 'else {if' (and a matching } later on) when
enforcing compound statements for such blocks.

One consequence of how it works now is that if I write:

if (a) {}
else if (b) {}
else if (c) {}
else {}

then use a tool I have to visualise C code in my syntax, it generates:

if a then
else
if b then
else
if c then
else
fi
fi
fi

The nested nature is revealed. If there were 50 'else if' links, the
output would disappear off to the right.

With elif, elsif etc, the compiler has the option to keep the internal
structure linear (which also means it will not put pressure on the stack
if somebody decides to write a million of them).
Kaz Kylheku
2024-09-24 22:36:53 UTC
Permalink
Post by Bart
Post by Kaz Kylheku
Post by Bart
(Maybe the language needs a construct like 'elif', as is used in
The language doesn't need such a construct in order for a compiler
to implement it internally.
You just have to treat the token sequence else if as a supertoken.
Doing it at the grammar level may require two symbols of lookahead,
which is a a problem for off-the-shelf parser generation tooling based
on LALR(1) and whatnot.
That sounds as much of a hack as making a special case for 'else if' so
that it doesn't need 'else {if' (and a matching } later on) when
enforcing compound statements for such blocks.
It's a hack, but you can completely hide it at the grammar level; you
can write your grammar with the assumption that there is an ELIF token,
so that the syntax is identical to that found in languages that have
elif or elsif. Just the lexical level, it is spelled by two words.
Post by Bart
if (a) {}
else if (b) {}
else if (c) {}
else {}
It behooves C processing tools to grok "else if" where it makes sense.
Post by Bart
if a then
else
if b then
else
if c then
else
fi
fi
fi
Note that in this type of language, an "elif" is helpful, because
every "else if" introduces an "if", which must be matched by its own
"fi", whereas an "elif" doesn't require its own closing keyword.

In other words, "elif" is more than just a contraction for "else if"; it
eliminates "fi".

In the preprocessor, it is different; there is an #endif.

If the above language has elif, then a conversion can be applied
by the rewrite rule

{if/elif} A then B else if C then [...] fi fi

->

{if/elif} A then B elif C then [...] fi

this can be repeatedly applied until there is no match for the
left hand side.
Post by Bart
The nested nature is revealed. If there were 50 'else if' links, the
output would disappear off to the right.
With elif, elsif etc, the compiler has the option to keep the internal
structure linear (which also means it will not put pressure on the stack
if somebody decides to write a million of them).
The option to keep the AST structure linear is there regardless,
as I pointed out; compilers writers can easily pretend that "else if"
is special.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Keith Thompson
2024-09-22 20:39:36 UTC
Permalink
[...]
Post by Bart
Post by Kaz Kylheku
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn it
on? Since -Wall -Wpedantic -Wextra doesn't report it.
The -Wmisleading-indentation option was added to gcc on 2015-05-12,
and incorporated into -Wall 2015-12-10. gcc 6.1.0 has the option
and includes it in -Wall; gcc 5.3.0 does not. (Are you using a gcc
release that old?) It uses the -ftabstop= option (defaulting to 8)
to determine whether indentation lines up or not.

Inconsistent tabstops and mixing of spaces and tabs can certainly
cause problems.
Post by Bart
It is a failure in the design of the language.
I wouldn't quite go that far, but I partly agree with you. Perl
requires braces on compound statements, and I've largely adopted
that style in my own C code. If C had required braces (requiring
a compound-statement in most contexts that currently require a
statement), certain errors would have been more difficult to make.
And you could still write one-line if statements in the cases
where they might be clearer:

if (cond1) { do_this(); }
if (cond2) { do_that(); }
if (cond3) { do_the_other(); }

However, there is zero chance that this will be changed in a future
version of C. It would break too much existing code. Which is
why we're discussing ways to write reliable code given the existing
language rules.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
David Brown
2024-09-23 06:16:07 UTC
Permalink
Post by Keith Thompson
[...]
Post by Bart
Post by Kaz Kylheku
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn it
on? Since -Wall -Wpedantic -Wextra doesn't report it.
The -Wmisleading-indentation option was added to gcc on 2015-05-12,
and incorporated into -Wall 2015-12-10. gcc 6.1.0 has the option
and includes it in -Wall; gcc 5.3.0 does not. (Are you using a gcc
release that old?) It uses the -ftabstop= option (defaulting to 8)
to determine whether indentation lines up or not.
Inconsistent tabstops and mixing of spaces and tabs can certainly
cause problems.
That would be detected quite easily if the default for -ftabstop were,
say, 27. Then the chance of accidentally matching indents with tabs and
spaces would be negligible.
Richard Harnden
2024-09-23 07:06:34 UTC
Permalink
Post by David Brown
Post by Keith Thompson
[...]
Post by Bart
Post by Kaz Kylheku
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn it
on? Since -Wall -Wpedantic -Wextra doesn't report it.
The -Wmisleading-indentation option was added to gcc on 2015-05-12,
and incorporated into -Wall 2015-12-10.  gcc 6.1.0 has the option
and includes it in -Wall; gcc 5.3.0 does not.  (Are you using a gcc
release that old?)  It uses the -ftabstop= option (defaulting to 8)
to determine whether indentation lines up or not.
Inconsistent tabstops and mixing of spaces and tabs can certainly
cause problems.
That would be detected quite easily if the default for -ftabstop were,
say, 27.  Then the chance of accidentally matching indents with tabs and
spaces would be negligible.
Isn't that the opposite of what you want, though?
David Brown
2024-09-23 09:14:07 UTC
Permalink
Post by Richard Harnden
Post by David Brown
Post by Keith Thompson
[...]
Post by Bart
Post by Kaz Kylheku
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn it
on? Since -Wall -Wpedantic -Wextra doesn't report it.
The -Wmisleading-indentation option was added to gcc on 2015-05-12,
and incorporated into -Wall 2015-12-10.  gcc 6.1.0 has the option
and includes it in -Wall; gcc 5.3.0 does not.  (Are you using a gcc
release that old?)  It uses the -ftabstop= option (defaulting to 8)
to determine whether indentation lines up or not.
Inconsistent tabstops and mixing of spaces and tabs can certainly
cause problems.
That would be detected quite easily if the default for -ftabstop were,
say, 27.  Then the chance of accidentally matching indents with tabs
and spaces would be negligible.
Isn't that the opposite of what you want, though?
What I would be looking for in this case is a warning if I had used tabs
and spaces (for indents) at different places in the code. If the tab
setting is a sensible choice - typically 4 or 8 spaces worth - then you
can easily have code that looks right (in the sense of having visual
indents that match the real block structure) with one setting and looks
wrong with a different setting.

For example, you might write this code :

<tb>if (test)
<tb><tb>foo();
< >< >bar();

You've made an error here - you had intended to have both calls within
the conditional. With 4 spaces per tab when you made the error, this
could be spotted by tools using tabstop settings of 4, or by a code
reviewer with those settings.

However, to tools or code reviewers with tabstop settings of 8, the code
would appear as:

<tb >if (test)
<tb ><tb >foo();
< >< >bar();

Now the indentation matches the syntactical structure, and the mistake
is missed.

With a tabstop of 27, the "if" and "bar()" lines do not match up, and
the mistake can be flagged.

Of course a tabstop of 27 is not necessary - anything other than a sane
value of 4 or 8 would catch almost anything. But having a bit of extra
distance also catches cases of tab then space typos.

And there could also be a warning that checked directly for mixes of
tabs and spaces in indents. But such mixes can happen when moving or
copying code between files, and there are some people who like to mix
8-space tabs with 4 explicit spaces in their code.
Richard Harnden
2024-09-23 10:37:34 UTC
Permalink
Post by David Brown
Post by Richard Harnden
Post by David Brown
Post by Keith Thompson
[...]
Post by Bart
Post by Kaz Kylheku
Also GCC has been able to diagnose misleading indentation for some
years now.
How many years was that out of the last 52? How exactly do you turn it
on? Since -Wall -Wpedantic -Wextra doesn't report it.
The -Wmisleading-indentation option was added to gcc on 2015-05-12,
and incorporated into -Wall 2015-12-10.  gcc 6.1.0 has the option
and includes it in -Wall; gcc 5.3.0 does not.  (Are you using a gcc
release that old?)  It uses the -ftabstop= option (defaulting to 8)
to determine whether indentation lines up or not.
Inconsistent tabstops and mixing of spaces and tabs can certainly
cause problems.
That would be detected quite easily if the default for -ftabstop
were, say, 27.  Then the chance of accidentally matching indents with
tabs and spaces would be negligible.
Isn't that the opposite of what you want, though?
What I would be looking for in this case is a warning if I had used tabs
and spaces (for indents) at different places in the code.  If the tab
setting is a sensible choice - typically 4 or 8 spaces worth - then you
can easily have code that looks right (in the sense of having visual
indents that match the real block structure) with one setting and looks
wrong with a different setting.
<tb>if (test)
<tb><tb>foo();
<  ><  >bar();
You've made an error here - you had intended to have both calls within
the conditional.  With 4 spaces per tab when you made the error, this
could be spotted by tools using tabstop settings of 4, or by a code
reviewer with those settings.
However, to tools or code reviewers with tabstop settings of 8, the code
<tb    >if (test)
<tb    ><tb    >foo();
<  ><  >bar();
Now the indentation matches the syntactical structure, and the mistake
is missed.
With a tabstop of 27, the "if" and "bar()" lines do not match up, and
the mistake can be flagged.
Of course a tabstop of 27 is not necessary - anything other than a sane
value of 4 or 8 would catch almost anything.  But having a bit of extra
distance also catches cases of tab then space typos.
And there could also be a warning that checked directly for mixes of
tabs and spaces in indents.  But such mixes can happen when moving or
copying code between files, and there are some people who like to mix
8-space tabs with 4 explicit spaces in their code.
If -ftabstops doesn't agree with your editor setting,
then gcc misses the errors, eg:

gcc, with the default -ftabstop=8, sees this ...

$ expand -t8 x.c
#include <stdio.h>

int main(void)
{
int x=1;

if ( x == 1 )
printf("x is 1\n");
else
printf("x is not 1\n"); // tabs
printf("x is %d\n", x); // spaces

return 0;
}

... and the indentation doesn't match up, so it's happy.

$ gcc -Wmisleading-indentation -ftabstop=8 x.c
(nothing)

But, in my editor, I see this ...

$ expand -t4 x.c
#include <stdio.h>

int main(void)
{
int x=1;

if ( x == 1 )
printf("x is 1\n");
else
printf("x is not 1\n"); // tabs
printf("x is %d\n", x); // spaces

return 0;
}

... and then indentation does match up, so I want the error flagged.
Which it does:

$ gcc -Wmisleading-indentation -ftabstop=4 x.c
x.c: In function ‘main’:
x.c:9:5: warning: this ‘else’ clause does not guard...
[-Wmisleading-indentation]
9 | else
| ^~~~
x.c:11:9: note: ...this statement, but the latter is misleadingly
indented as if it were guarded by the ‘else’
11 | printf("x is %d\n", x); // spaces
| ^~~~~~

So, to me anyway, telling gcc that tabstops are 27 would suppress all
the useful warnings.
David Brown
2024-09-23 12:22:30 UTC
Permalink
Post by Richard Harnden
So, to me anyway, telling gcc that tabstops are 27 would suppress all
the useful warnings.
I see what you mean.

Fair enough - it seems that picking a tabstop setting that matches your
editor settings could catch some mistakes that a different tabstop
setting would not. Equally, I think from my example, having a different
tabstop setting would catch other errors that one matching your editor
would not.

And in my brief testing, using gcc 13, it failed to catch several cases
of indentation mismatches, regardless of the tabstop setting, which is a
bit disappointing.

I think perhaps the best solution would be for gcc to warn about
space/tab mismatches as well, regardless of the tabstop settings.
Kenny McCormack
2024-09-22 16:03:17 UTC
Permalink
In article <***@kylheku.com>,
Kaz Kylheku <643-408-***@kylheku.com> wrote:
...
Post by Mark Summerfield
if (failed)
WARN("failed because...");
else
ok++;
attempts++; // automatic deindent
When I add a line after ok++, it deindents it to be at the same
indentation level as the if, before letting me type any content into it.
OK, I lied about the super advanced from the future. It's just Vim.
Also GCC has been able to diagnose misleading indentation for some
years now.
Between those two, there is nothing to worry about; just concentrate on
whether it looks prettier without the braces or with.
Actually, there are more than a few C shibboleths that date back to the days
of yore when both editors and C compilers were a lot less capable than they
are today - with the result being, as you imply, that they are, nowadays,
pretty much irrelevant.

One such example is the old chestnut of:

if (a = 0) ...

My old Turbo C compiler caught this back in 1987.

And yet people still talk about it today.
--
When I was growing up we called them "retards", but that's not PC anymore.
Now, we just call them "Trump Voters".

The question is, of course, how much longer it will be until that term is also un-PC.
David Brown
2024-09-22 16:03:46 UTC
Permalink
Post by Mark Summerfield
Post by David Brown
I am not suggesting overuse of braces. I am suggesting /good/ use of them.
<https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html>
That's perhaps the most famous example of the havoc caused by omitting
useful braces.
Consistency and clarity is important. So is maintainability. Suppose,
for example, you want to add a line "attempts++;" alongside the "ok++;"
line. When the braces are there, the change is exactly that - add the
new line you want. Without the original braces, you are now making
changes to the structural syntax of the code as well when you add in
original braces - or you are making a mistake in the code.
if (failed)
WARN("failed because...");
else
ok++;
attempts++; // automatic deindent
When I add a line after ok++, it deindents it to be at the same
indentation level as the if, before letting me type any content into it.
OK, I lied about the super advanced from the future. It's just Vim.
Also GCC has been able to diagnose misleading indentation for some
years now.
Between those two, there is nothing to worry about; just concentrate on
whether it looks prettier without the braces or with.
I am happiest with a bracing style that looks good (in my subjective
opinion), is easily understandable, is hard for humans to misinterpret,
is automated to a large extent by many editors, and is checked by the
compiler. I agree that mistakes due to indentation errors should be a
thing of the past for people who use decent modern tools. But I'm a
seatbelt and airbag kind of programmer, at least when there is no
runtime cost - I prefer a method that is inherently hard to get wrong
and is /also/ checked and automated by tools.
Tim Rentsch
2024-09-28 12:02:05 UTC
Permalink
Andrey Tarasevich <***@hotmail.com> writes:

[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
Michael S
2024-09-28 17:30:48 UTC
Permalink
On Sat, 28 Sep 2024 05:02:05 -0700
Post by Tim Rentsch
[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
{ at the same level of indentation as its matching }
Tim Rentsch
2024-09-29 04:53:06 UTC
Permalink
Post by Michael S
On Sat, 28 Sep 2024 05:02:05 -0700
Post by Tim Rentsch
[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
{ at the same level of indentation as its matching }
Certainly it is true that the layout style shown has the open
brace at the same level of indentation as the matching close
brace. What about that property makes this layout "more
readable"? The statement given sounds like a tautology -
I don't see that any new information has been added.
Michael S
2024-09-29 09:48:35 UTC
Permalink
On Sat, 28 Sep 2024 21:53:06 -0700
Post by Tim Rentsch
Post by Michael S
On Sat, 28 Sep 2024 05:02:05 -0700
Post by Tim Rentsch
[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
{ at the same level of indentation as its matching }
Certainly it is true that the layout style shown has the open
brace at the same level of indentation as the matching close
brace. What about that property makes this layout "more
readable"? The statement given sounds like a tautology -
I don't see that any new information has been added.
It makes it easier to see where block starts and where it ends. Opening
{ followed by empty line is more bold visually than 'if something { ' or
then '} else {'.

Now, I can live with both styles, but can see why many people prefer
style advocated by Andrey.
Tim Rentsch
2024-09-30 02:18:54 UTC
Permalink
Post by Michael S
On Sat, 28 Sep 2024 21:53:06 -0700
Post by Tim Rentsch
Post by Michael S
On Sat, 28 Sep 2024 05:02:05 -0700
Post by Tim Rentsch
[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
{ at the same level of indentation as its matching }
Certainly it is true that the layout style shown has the open
brace at the same level of indentation as the matching close
brace. What about that property makes this layout "more
readable"? The statement given sounds like a tautology -
I don't see that any new information has been added.
It makes it easier to see where block starts and where it ends.
Opening { followed by empty line is more bold visually than 'if
something { ' or then '} else {'.
Certainly having an open brace on a line by itself stands out
more than if the open brace were written at the end of an if()
or while() line.

Whether that makes it easier to see where a block starts is
something that can be measured, and also might be reader
dependent. For myself I find that having open braces on lines by
themselves interferes with my ease of reading. And that has been
true since before I ever programmed in C.
Post by Michael S
Now, I can live with both styles, but can see why many people
prefer style advocated by Andrey.
I've made a serious effort over the years to find out why people
who prefer the Andrey style are so definite that it is somehow
better. I have yet to get an illuminating answer to that
question. I've gotten various forms of non-answer arguments, and
what seem to me to be circular answers (like saying it is more
readable). I understand that they prefer it; I still don't
understand why they prefer it. I acknowledge your point that
they think the open brace on a line by itself somehow helps with
their reading. But I still don't understand why they think that.
Alan Mackenzie
2024-09-30 15:05:39 UTC
Permalink
Post by Michael S
On Sat, 28 Sep 2024 21:53:06 -0700
Post by Tim Rentsch
Post by Michael S
On Sat, 28 Sep 2024 05:02:05 -0700
Post by Tim Rentsch
[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
{ at the same level of indentation as its matching }
Certainly it is true that the layout style shown has the open
brace at the same level of indentation as the matching close
brace. What about that property makes this layout "more
readable"? The statement given sounds like a tautology -
I don't see that any new information has been added.
It makes it easier to see where block starts and where it ends. Opening
{ followed by empty line is more bold visually than 'if something { ' or
then '} else {'.
Now, I can live with both styles, but can see why many people prefer
style advocated by Andrey.
I think it objectively true that superfluous compound statements and
opening braces on lines of their own make code less readable. Not by a
lot, but by enough.

The reason is that people are not struggling to read individual
statements (apart from raw beginners), they are struggling to read a
whole program. With the lots-of-blank-lines styles advocated by some,
less of a program will fit on a screen than with more economical styles.
That means more scrolling up and down to see what should be closely
related parts of the program.

This is more true of modern IDEs, where only a small part of the screen
is devoted to the program text, than good text editors. For example, in
Emacs (using Follow Mode) I can get 195 consecutive lines displayed
legibly and usably on my screen at once. But even with that, having
superfluous vertical space occasionally makes me have to scroll.

At a high level of abstraction, what makes code difficult to understand
and debug is having to look somewhere else. The
superfluous-vertical-space styles increase that difficulty, if only a
little.
--
Alan Mackenzie (Nuremberg, Germany).
Andrey Tarasevich
2024-09-29 04:02:11 UTC
Permalink
Post by Tim Rentsch
[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
Er... The answer to his question is already present in the quoted
portion of my post. "The vertical spacing introduced..."
--
Best regards,
Andrey
Tim Rentsch
2024-09-29 05:47:16 UTC
Permalink
Post by Andrey Tarasevich
Post by Tim Rentsch
[...]
And don't use "Egyptian" braces [the style used in the
first edition of The C Programming Language, by Kernighan
and Ritchie].
This is the proper formatting style with braces
if (failed)
{
...
}
else
{
...
}
The vertical spacing introduced by the `{` line provides
separation between condition and the branch, which makes
your code much more readable. [...]
What qualities does this layout style have that make it "more
readable", other than it being one that you like or prefer?
Er... The answer to his question is already present in the quoted
portion of my post. "The vertical spacing introduced..."
Does that mean you think this

if (failed) {

...

} else {

...

}

is just as readable? Or is it something besides the
vertical spacing that bears on your "more readable"
judgment?
Andrey Tarasevich
2024-09-29 14:41:14 UTC
Permalink
On 09/28/24 10:47 PM, Tim Rentsch wrote:
efer?
Post by Tim Rentsch
Post by Andrey Tarasevich
Er... The answer to his question is already present in the quoted
portion of my post. "The vertical spacing introduced..."
Does that mean you think this
if (failed) {
...
} else {
...
}
is just as readable? Or is it something besides the
vertical spacing that bears on your "more readable"
judgment?
No, the spacing in question is the spacing between the `if` condition
and the first line of the the first compound statement.

This is unreadable and unacceptable

if (condition) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}

for (abc; def; ghi) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}

This is _immensely_ more readable

if (condition)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}

for (abc; def; fgh)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}

This readability problem exists one the other end with struct
declarations and `do{}while` syntax as well

typedef struct MyStruct
{
int a;
double b;
char c;
} MyStruct; /* <-- Bad! No vertical separation! */

do
{
whatever1;
whatever2;
} while (condition); /* <-- Bad! No vertical separation! */

I don't have a perfect solution for this variation of the same issue.
So, I tend to use

typedef struct MyStruct
{
int a;
double b;
char c;

} MyStruct;

do
{
whatever1;
whatever2;

} while (condition);

although admittedly this has its own drawbacks.
--
Best regards,
Andrey
Michael S
2024-09-29 15:04:31 UTC
Permalink
On Sun, 29 Sep 2024 07:41:14 -0700
Post by Andrey Tarasevich
efer?
Post by Tim Rentsch
Post by Andrey Tarasevich
Er... The answer to his question is already present in the quoted
portion of my post. "The vertical spacing introduced..."
Does that mean you think this
if (failed) {
...
} else {
...
}
is just as readable? Or is it something besides the
vertical spacing that bears on your "more readable"
judgment?
No, the spacing in question is the spacing between the `if` condition
and the first line of the the first compound statement.
This is unreadable and unacceptable
if (condition) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
for (abc; def; ghi) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
This is _immensely_ more readable
if (condition)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
for (abc; def; fgh)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
It seems, you didn't understand the question.
Tim was asking about your opining w.r.t.
if (condition) {

whatever1;
whatever2;
}
Scott Lurndal
2024-09-29 18:30:30 UTC
Permalink
Post by Andrey Tarasevich
efer?
Post by Tim Rentsch
Post by Andrey Tarasevich
Er... The answer to his question is already present in the quoted
portion of my post. "The vertical spacing introduced..."
Does that mean you think this
if (failed) {
...
} else {
...
}
is just as readable? Or is it something besides the
vertical spacing that bears on your "more readable"
judgment?
No, the spacing in question is the spacing between the `if` condition
and the first line of the the first compound statement.
This is unreadable and unacceptable
if (condition) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
for (abc; def; ghi) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
This is _immensely_ more readable
To you. I find it less readable than the above.

For those of us who started with ed/vi, certain paradigms
evolved - such as ensuring the function name for a function
definition starts in column 1 so you can easily find it
using /^function-name, so

int
main(...)
{
}

is preferrred over

int main(...) {
}


Likewise, the opening brace for the function should start
a line (supporting the '[[' and ']]' vim commands).

(and '%' use useful to match braces).

Indentation should be a sufficient visual cue without wasting
whitespace on useless blank lines.

f = fdopen(fd, "r");
if (f == NULL) {
lp->log("Unexpected error re-opening '%s': %s\n",
filename, strerror(errno));
close(fd);
goto done;
}
Keith Thompson
2024-09-29 23:39:31 UTC
Permalink
Andrey Tarasevich <***@hotmail.com> writes:
[...]
Post by Andrey Tarasevich
This is unreadable and unacceptable
if (condition) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
for (abc; def; ghi) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
This is _immensely_ more readable
if (condition)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
for (abc; def; fgh)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
[...]

Andrey, I hope you're aware that you're stating your own personal
preferences as if they were incontrovertible fact.

Readability is a combination of the text being read and the person
reading it. I accept without question that *you* find K&R-style
brace placement "unreadable and unacceptable". A lot of experienced
C programmers, myself included, either prefer the K&R style or
find both styles more or less equally readable. And many prefer
vertically aligned braces but can deal with K&R-style braces.

I have some quirks of my own, things that most people accept but
I hate, so I get where you're coming from. But I suggest it would
be good for you to be aware that your preferences are something of
an outlier, and that arguing about it isn't going to be productive.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Kaz Kylheku
2024-09-30 02:29:10 UTC
Permalink
Post by Keith Thompson
[...]
Post by Andrey Tarasevich
This is unreadable and unacceptable
if (condition) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
for (abc; def; ghi) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
This is _immensely_ more readable
if (condition)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
for (abc; def; fgh)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
[...]
Andrey, I hope you're aware that you're stating your own personal
preferences as if they were incontrovertible fact.
Readability is a combination of the text being read and the person
reading it. I accept without question that *you* find K&R-style
brace placement "unreadable and unacceptable". A lot of experienced
C programmers, myself included, either prefer the K&R style or
find both styles more or less equally readable. And many prefer
vertically aligned braces but can deal with K&R-style braces.
For what it may be worth, the K&R style is pretty much baked into the
Awk language. These two Awk programs are not equivalent:

/foo/
{
foo++
}

vs:

/foo/ {
foo++
}

The first one will print every record which contains a match
for the regular expression foo, and count every record.

The second will increment foo for every record that matches foo.

It is an undeniable fact that alignment and grouping is important
in visual design, and that use of these elements (and others)
is important in creating signs and displays that are easy to
grok at a glance.

Aligning opening and closing punctuators in programming is going
overboard though.

Here is why: we have already decided that these punctuators are
not helpful in helping us grok the structure of the code, and
instead rely on indentation.

The reason that the punctuators are not helpful is not because they are
not vertically aligned.

However, if we take away indentation from all the code other
than the braces, then the vertical alignment does help recover
some of the lost readability:

Compare:

if (condition) {
for (abc; def; fgh) {
if (nested-condition) {
whatever1;
whatever2;
}
}
} else {
whatever3;
}

versus:

if (condition)
{
for (abc; def; fgh)
{
if (nested-condition)
{
whatever1;
whatever2;
}
}
}
else
{
whatever3;
}

But the likely reason for this is that the aligned braces increase the
amount of correct indentation. The structural cue from indentation is
only coming from the braces here, so if half of them are not indented,
then half that signal is gone.

I can sort of see why this identation signal from the opening braces
would be important even if the code were fully indented, to someone who
has some sort of cognitive quirk.

Also, I can see how the structure is more nicely conveyed when the
eopening braces are indented, if the reader temporarily blocks out
the visibility of the code and focuses on only seeing the braces:

This:

{

{

{


}
}
}

{

}

versus:

{
{
{


}
}
} {

}

In other words, the vertical braces enable a mode of visually filtering
the code that may be of use to some. (Though, to me, choosing to see
the braces while suppressing the rest of the code seems wrongheaded. Or
wrong-eyed?)

It is mainly an indentation signal though; the main aspect is not the
vertical alignment, but the correct indentation nesting. All the
matching braces are still vertically aligned in this code also, yet
the indentation is haphazard and unhelpful:

if (condition)
{
for (abc; def; fgh)
{
if (nested-condition)
{
whatever1;
whatever2;
}
}
}
else
{
whatever3;
}
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Janis Papanagnou
2024-09-30 09:26:31 UTC
Permalink
First, I want to re-emphasize that valuation of styles lies in the
eye of the beholder. Then, for practical purposes, there's usually
(coding-)standards defined [in professional contexts] that define
the rules folks have to follow. While in private contexts everyone
is free to follow own personal preferences.
Post by Kaz Kylheku
[...]
For what it may be worth, the K&R style is pretty much baked into the
/foo/
{
foo++
}
/foo/ {
foo++
}
For the readers unfamiliar with Awk it should be mentioned that
this is a consequence of Awk's implicit defaults.

/foo/ is equivalent to /foo/ { print $0 }

and

{ foo++ } is equivalent to 'true' { foo++ }

(using the informal 'true' as placeholder for any true condition).

Thus you have to put the opening braces on the same line as the
condition to indicate that condition and action belong together.
Post by Kaz Kylheku
[...]
It is an undeniable fact that alignment and grouping is important
in visual design, and that use of these elements (and others)
is important in creating signs and displays that are easy to
grok at a glance.
Sic!
Post by Kaz Kylheku
[...]
Also, I can see how the structure is more nicely conveyed when the
eopening braces are indented, if the reader temporarily blocks out
{
{
{
}
}
}
{
}
As far as I'm concerned, it's not only the braces but also the
placement of the associated control-structure keywords that
matters.

To _quickly_ *assert* the code structure the following...
Post by Kaz Kylheku
{
{
{
}
}
} {
}
...is indeed [unnecessarily] suboptimal! (And adding the keywords
doesn't make that situation better.) Having tool support (like
an editor's syntax highlighting) might alleviate that issue (but
does not solve it).

(Maybe it's to some degree comparable with the difference between
ragged layout of texts vs. text that has consistent line lengths
or is even block-justified.)
Post by Kaz Kylheku
In other words, the vertical braces enable a mode of visually filtering
the code that may be of use to some. (Though, to me, choosing to see
the braces while suppressing the rest of the code seems wrongheaded. Or
wrong-eyed?)
There's nothing suppressed. (Moreover I think any tries to value
other preferences with psychological assumptions and personal
valuations doesn't serve the discussions.)

BTW, a friend of mine (a long year experienced CS professional)
prefers [to my astonishment] a formatting I've not (or certainly
not widely) seen before...

while (cond)
{
stmt1;
stmt2;
}

Also aligned (but differently).
Post by Kaz Kylheku
[...]
It might make sense - besides visual or "psychological" explanations -
to also include people's experiences with or influences from other
programming languages they use. People may be used to structures like

if condition then
begin
...
end
else
...

which can be found in many languages (Algol, Pascal, ...), or from
the Unix [standard] shell where syntax requirements foster structures
like

if command1
then
command2
else
command3
fi


My personal preferences are best supported by a syntax that you
find in Algol 68, Eiffel (or Unix shell), where you usually don't
need any sort of brackets in control structures, and where there's
thus less dispute about where to place the 'opening block' symbol.

Janis
Tim Rentsch
2024-09-30 01:39:06 UTC
Permalink
Post by Andrey Tarasevich
efer?
Post by Tim Rentsch
Post by Andrey Tarasevich
Er... The answer to his question is already present in the quoted
portion of my post. "The vertical spacing introduced..."
Does that mean you think this
if (failed) {
...
} else {
...
}
is just as readable? Or is it something besides the
vertical spacing that bears on your "more readable"
judgment?
No, the spacing in question is the spacing between the `if`
condition and the first line of the the first compound statement.
My question was misquoted. I was asking about this:

if (failed) {

...

} else {

...

}

where there is a blank line after the "if()" line, both before
and after the "} else {" line, and before the line with the final
closing brace.

This layout has as much vertical separation as the layout style
you prefer (and one more blank line at the end). Do you think it
is just as readable as your preferred layout? Or is it something
besides the vertical spacing that bears on your "more readable"
judgment?
Kaz Kylheku
2024-09-30 02:03:20 UTC
Permalink
Post by Andrey Tarasevich
efer?
Post by Tim Rentsch
Post by Andrey Tarasevich
Er... The answer to his question is already present in the quoted
portion of my post. "The vertical spacing introduced..."
Does that mean you think this
if (failed) {
...
} else {
...
}
is just as readable? Or is it something besides the
vertical spacing that bears on your "more readable"
judgment?
No, the spacing in question is the spacing between the `if` condition
and the first line of the the first compound statement.
This is unreadable and unacceptable
if (condition) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
for (abc; def; ghi) {
whatever1; /* <-- Bad! No vertical separation! */
whatever2;
}
This is _immensely_ more readable
if (condition)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
for (abc; def; fgh)
{ /* <-- Good! Vertical space */
whatever1;
whatever2;
}
I don't see a readability difference. I'm not a kook.

Both examples use correct indentation.

The braces are placed such that the indentation does not lie.

If that is the case, you don't have to care how exactly they
are placed.

When I look at this code, my brain mostly sees it like this:

if (condition)
whatever1; /* <-- Bad! No vertical separation! */
whatever2;

for (abc; def; ghi)
whatever1; /* <-- Bad! No vertical separation! */
whatever2;

if (condition)
/* <-- Good! Vertical space */
whatever1;
whatever2;


for (abc; def; fgh)
/* <-- Good! Vertical space */
whatever1;
whatever2;

except that if there is something deceptive with the braces going on,
there is a good chance my brain will still alert me to it.

"Cuddled braces" is a very popular formatting style; it behooves you to
get used to it.
Post by Andrey Tarasevich
This readability problem exists one the other end with struct
declarations and `do{}while` syntax as well
typedef struct MyStruct
{
int a;
double b;
char c;
} MyStruct; /* <-- Bad! No vertical separation! */
do
{
whatever1;
whatever2;
} while (condition); /* <-- Bad! No vertical separation! */
I don't have a perfect solution for this variation of the same issue.
So, I tend to use
I don't understand what would be wrong with:

do
{
whatever1;
whatever2;
}
while (condition); /* <-- Good! Vertical separation! */

For the typedef you can always do this:

typedef struct MyStruct MyStruct;

struct MyStruct
{
int a;
double b;
char c;
};
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
David Brown
2024-09-30 11:17:45 UTC
Permalink
Post by Andrey Tarasevich
efer?
Post by Tim Rentsch
Post by Andrey Tarasevich
Er... The answer to his question is already present in the quoted
portion of my post.  "The vertical spacing introduced..."
Does that mean you think this
     if (failed) {
       ...
     } else {
       ...
     }
is just as readable?  Or is it something besides the
vertical spacing that bears on your "more readable"
judgment?
No, the spacing in question is the spacing between the `if` condition
and the first line of the the first compound statement.
This is unreadable and unacceptable
I hope you are aware that that is, at best, a personal opinion? Given
that a great many C programmers write code that way and find it both
readable and acceptable - indeed preferable to your own style - your
claim is obviously factually incorrect.

If you can provide evidence in the form of studies or statistical data
that demonstrate that your style is significantly easier to read for
many people, or leads to fewer errors in code, then I think many people
here would be interested in that. But as it stands, your post is as
useful as telling us that the best flavour of ice-cream is obviously
strawberry and that chocolate ice-cream is inedible.
Post by Andrey Tarasevich
This readability problem exists one the other end with struct
declarations and `do{}while` syntax as well
I don't have a perfect solution for this variation of the same issue.
So, I tend to use
  typedef struct MyStruct
  {
    int a;
    double b;
    char c;
  } MyStruct;
  do
  {
    whatever1;
    whatever2;
  } while (condition);
although admittedly this has its own drawbacks.
Note that the "one true brace" style has no problem here and is
consistent in these cases. Consistency is not necessarily of overriding
importance, but it often helps readability.
Bart
2024-09-21 09:13:00 UTC
Permalink
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
total++;
if (failed) {
WARN("failed because...");
} else
ok++;
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
Remove the semicolon at the end of the macro.

As it is, it compiles to:

if (failed) do {...} while 0;; else ok++:

There are two semicolons together, the second terminates the whole if
statement, leaving an open 'else'.
Mark Summerfield
2024-09-21 09:53:29 UTC
Permalink
Thank you Bart & Ike: I removed the ; and now the macro works great.
Ike Naar
2024-09-21 09:15:40 UTC
Permalink
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
[...]
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
After expansion of the WARN macro there are two semicolons before the 'else'.
The first semicolon is from the

} while (0);

line, the second is from the


WARN("failed because...");

line.
Removing the semicolon from one of these two lines fixes the compiler error.
Keith Thompson
2024-09-21 21:44:26 UTC
Permalink
Post by Ike Naar
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
[...]
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
After expansion of the WARN macro there are two semicolons before the 'else'.
The first semicolon is from the
} while (0);
line, the second is from the
WARN("failed because...");
line.
Removing the semicolon from one of these two lines fixes the compiler error.
And removing the semicolon from the macro definition is the only
sensible way to do this.

The do ... while (condition) idiom is the conventional way to write a
macro that can be used in any context that requires a statement. Adding
the semicolon in the macro definition and expecting users to omit the
semicolon when invoking it is not a good idea.

See question 10.4 of the comp.lang.c FAQ, <https://www.c-faq.com/>.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Tim Rentsch
2024-09-21 13:07:15 UTC
Permalink
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
total++;
if (failed) {
WARN("failed because...");
} else
ok++;
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
You can define WARN() this way

#define WARN(...) ( \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__), \
fprintf(stderr, __VA_ARGS__) \
)

and it will work as you want it to.
Keith Thompson
2024-09-21 22:55:12 UTC
Permalink
Post by Tim Rentsch
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
total++;
if (failed) {
WARN("failed because...");
} else
ok++;
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
You can define WARN() this way
#define WARN(...) ( \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__), \
fprintf(stderr, __VA_ARGS__) \
)
and it will work as you want it to.
Good point. To expand on that, the do/while trick (without the trailing
semicolon) is the usual way to write a macro that can be used anywhere a
statement can appear. But it's not necessary if all you want is a
sequence of expression statements. In that case, you can write the
expression statements (terminated by semicolons) as expressions
(separated by comma operators and enclosed in parentheses), and the
whole expansion is a single expression that can be used in an expression
statement. The macro can then be used in more contexts, since its
expansion is an expression (though that's not likely to matter in this
case).

An if/else can be turned into a conditional operator, which also gives
you an expression, but there's no expression equivalent for most control
flow constructs (loops, return, etc.). That's where the do/while trick
becomes necessary.

For this example (two fprintf calls), you can use either do/while or a
comma operator. You might consider using the do/while in case you might
want to add control flow later. If you have several similar macros,
there's something to be said for being consistent.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Andrey Tarasevich
2024-09-21 19:17:15 UTC
Permalink
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
total++;
if (failed) {
WARN("failed because...");
} else
ok++;
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
The whole idea of `do { ... } while(false)` idiom for writing complex
macros is based on _not_ including that `;` after `while(false)` into
the macro. Meanwhile, you botched the whole thing by adding that `;` there.

Remove the trailing `;` from the macro and everything will work as you
want it to.
--
Best regards,
Andrey
Blue-Maned_Hawk
2024-09-21 21:18:07 UTC
Permalink
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
total++;
if (failed) {
WARN("failed because...");
} else
ok++;
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
Since the initial problem has already been solved by other messages,
here's some extra completely unsolicited advice that you are free to
ignore:

If you intend for this macro to be invoked like how one would invoke the
printf function (i.e. the arguments consisting of a format string literal
followed by arguments to be formatted into it), you could get away with
defining it like this instead:

#define WARN(msg, ...) (fprintf(stderr, "%s#%d: " msg, __FILE__, __LINE__
__VA_OPT__(,) __VA_ARGS__))

This would break if you try to invoke it with a nonliteral string, because
this takes advantage of preprocessor adjacent string literal
concatenation, but modern compilers tend to complain mightily if you try
that anyway. It would have the advantage of expanding to an expression
instead, which is often more beneficial for macros because it permits more
flexibility in placement (something that i find unlikely to be relevant
for this particular one, but which can't really particularly hurt to have
anyway).
--
Blue-Maned_Hawk│shortens to Hawk│/blu.mɛin.dʰak/│he/him/his/himself/Mr.
blue-maned_hawk.srht.site
How do i run in these marrowy clogs?
Tim Rentsch
2024-09-24 13:18:08 UTC
Permalink
Post by Blue-Maned_Hawk
Post by Mark Summerfield
#define WARN(...) \
do { \
fprintf(stderr, "%s#%d: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while (0);
total++;
if (failed) {
WARN("failed because...");
} else
ok++;
total++;
if (failed)
WARN("failed because...");
else
ok++;
error: 'else' without a previous 'if'
Since the initial problem has already been solved by other messages,
here's some extra completely unsolicited advice that you are free to
If you intend for this macro to be invoked like how one would
invoke the printf function (i.e. the arguments consisting of a
format string literal followed by arguments to be formatted into
#define WARN(msg, ...) (fprintf(stderr, "%s#%d: " msg, __FILE__, __LINE__
__VA_OPT__(,) __VA_ARGS__))
This would break if you try to invoke it with a nonliteral string,
because this takes advantage of preprocessor adjacent string
literal concatenation, but modern compilers tend to complain
mightily if you try that anyway. It would have the advantage of
expanding to an expression instead, which is often more beneficial
for macros because it permits more flexibility in placement
(something that i find unlikely to be relevant for this particular
one, but which can't really particularly hurt to have anyway).
The alternative below works without needing __VA_OPT__, in earlier
C standards including C90.


#include <stdarg.h>
#include <stdio.h>

#define WARN(...) (warning_with_origin( __FILE__, __LINE__, __VA_ARGS__ ))

int
warning_with_origin( const char *file, long line, const char *format, ... ){
va_list ap;

int a = (va_start( ap, format ), 0);
int b = a < 0 ? a : fprintf( stderr, "%s#%ld: ", file, line );
int c = b < 0 ? b : vfprintf( stderr, format, ap );
int d = c < 0 ? c : fprintf( stderr, "\n" );

return va_end( ap ), d < 0 ? d : a + b + c + d;
}
Loading...