Hacker News new | ask | show | jobs
by kevin_thibedeau 4037 days ago
Its not so disturbing when you consider that braces aren't special cased in the C grammar. They group statements so they can be used together where a statement is needed. From the grammar's perspective the "normal" way is without braces. It's just that all the C-alikes have gone a different direction with the way braces are parsed leading everyone to regard the original behavior in C as ugly warts.
1 comments

for, if, and while without curly braces for single statement blocks are easily one of the worst things about C. It bites you in the ass every time. The balance between its utility and its capacity to cause bugs is so one sided, I don't understand why it's even taught to beginners. If you are teaching a new programmer that saving keystrokes is important, you're on the fast track to creating a shitty programmer.
That's pretty severe. Written with spacing, its really pretty clear what is meant by

   if (condition)
      Foo(x)
Braces are, in my opinion, an unfortunate necessity in some cases. They are a much larger cause of error than NOT using them ever could be.

An ideal IDE would make blocking visible (background tone change etc), and braces could be emitted automatically by the IDE without ever cluttering up the code shown to the programmer.

But tying everyone to a single IDE is never going to happen. The language is out there. It's going to stay backward compatible forever.

How could the presence of braces cause a worse error than no braces? Code compiles when you completely omit braces but put more than one statement underneath. The error is logical, not syntactical.

But if you have an open brace without a matching close brace, that's a compile error. What other error are you referring to?

How can you know that you won't add more statements to the block? Why have a special case at all? For me it's just become muscle memory to add the braces. It's a risk with exactly zero upside to omit braces.

The only problem with this is if/when someone comes along and doesn't notice the missing braces and does

   if (condition)
      Foo(x)
      Bar(x)
Expecting Bar(x) to be part of the conditional. This can and does happen.
I hear folks say that, but don't encounter it in the wild. Maybe once in 20 years so far. That construct, reading it just now, just screams out at me "Indentation error!"

Anyway it nicely illustrates the need to get braces out of there altogether. The programmers' intent is obvious; let the IDE 'make it so' by emitting braces in the generated code.

> I hear folks say that, but don't encounter it in the wild. Maybe once in 20 years so far.

It was the cause of the "goto fail" SSL bug that affected both of Apple's operating systems last year: https://nakedsecurity.sophos.com/2014/02/24/anatomy-of-a-got...

So I'd say it's rare, but it happens. And when it happens, the effects can be pretty big.

I've never seen (in code I've worked on)

    if (condition)
        Foo(x);
        Bar(x);
But I have seen

    if(condition1)
        if(condition2)
            if(condition3 && condition4)
                Foo();
This upset the old ARM compiler I was working on and it decided to skip some of the conditions. I fixed the bug, related to this code, by adding braces:

    if(condition1)
    {
        if(condition2)
        {
            if(condition3 && condition4)
            {
                Foo();
            }
        }
    }
So this is why I always put braces to define scope. Although, in general, both of these types of bugs are uncommon.

Honestly, the more pervasive problem that comes up is the eventual addition of new code adds noise to diffs. Like if I have a condition with a single statement

    if (condition)
        Foo(x);
And I add something to it, I have to add braces and it pollutes the diff with stuff that isn't really related to what I'm changing.

    if (condition)
    {
        Foo(x);
        Bar();
    }
"This upset the old ARM compiler I was working on and it decided to skip some of the conditions."

Do what you need to work around a known compiler bug, of course, but that is definitively a compiler bug. The meaning is unambiguous and consistent in the C standard and every implementation I've encountered. I'm not comfortable with the assertion that changing your coding style here makes you less susceptible to compiler bugs in general.

I agree with you - I can count the number of times I've seen it in my life on one hand - but ever since the Apple bug, lots of people use it as a club to hit people over the head with, to enforce braces everywhere.

There seems to be a logical error to me. An indentation mistake - something that can be caught trivially by a linter - is not significantly different by nature than any other single-character mistake, like an incorrect constant or misspelled identifier (harder to find with a linter). But because it was at the root of a specific flaw, it's become larger than life.

non-bracket is useful and informative in some cases when used properly (your local style guide takes precedence of course). I would never write

   if (condition)
      Foo(x)
for the reasons you said. But it can be very useful for a block of "single liners":

  /* clean up input before passing it to flaky_external_module() */

  for(; !isspace(*p); ++p); 
  if (!isdigit(*p)) return INPUT_ERR;
  for (char *i = p; *i; i++) *i = toupper(*i);
  ...

  flaky_external_module(p);

Basically a small block (that pretty much fits in your fovea) that does a bunch of minor tasks. Spacing them out would actually confuse the code.
I contend that the brackets always make the code more readable, without exception. It's the normal case. All other variations make you think "something special is happening here, I'm going to have to parse this carefully". The for with a semicolon at the end is easy to overlook. The return in the middle of a function in the middle of a line is easy to overlook.

Spacing code out makes it more readable and maintainable, not less. It brings consistency, and it is more prepared for the inevitable change. I think maintenance is the driver of all code style. When you make tight one liners or forgo braces, or use the ? And : operators instead of if and else, you're not really saving time, you are deferring work, in a lot of cases to another programmer.

Well, as I said, these determinations are up to the house style.

I prefer that blocks of code hold together -- think of them as paragraphs. Spacing each sentence of a paragraph out is similarly confusing. But as you say, YMMV.

I find return is_valid(result) ? result : ERR_CODE; common and clear, but perhaps you don't.

I do think that any style guide should forbid while and do..while simply because for has become by far the looping construct of choice in C.

In all cases the point should be correctness and clarity, not showing off that you use unusual language features.