I'm glad Python (with semantic whitespace) and Go (with gofmt) solve this problem.
I'm glad Python (with semantic whitespace) and Go (with gofmt) solve this problem.
Please. I'm as big a C apologist as you'll find and even I can think of six or nine thing objectively worse about the language.
This issue is merely a great bike shed because it allows all of us rabble to join in on a discussion about "compiler" technology.
Look: it's a good warning. People should clearly use it. It probably should have been written long ago, and probably would have if our editors hadn't been enforcing this since time immemorial.
But optional braces are perhaps the most pointless anti-feature in C. The only benefit is a minor (and subjective) improvement in aesthetics.
Sometimes you can write code that looks "prettier", at the expensive of the ability to read and reason about it. Optional braces are frequently used for this effect. Yes, optional braces allow you to fit more code on the screen with less noise—and therefore could be thought to enhance some kind of readability. But at the same time, they require you to think harder about the grouping of the code around them. Unless you've got a reformatting linter, you could have code like this:
if(foo)
bar; baz;
quux;
and optional braces require an extra subroutine to be constantly running in your head, looking for those mis-arranged `baz`es that will get executed anyway. That cognitive load detracts from your ability to read and reason about the code.(What'd be really interesting, in my opinion, would be to make C's braceless blocks, and only braceless blocks, have semantic-whitespace. Then the above would be able to be easily reasoned through: `baz` is part of the conditional, because it's on the same line. But this breaks a lot of rather old and inflexible assumptions about how C is parsed, that macro-writers et al depend on.)
>I'm glad Python (with semantic whitespace)... solve this problem.
Python solved it....then added the problem of making things you can't even see semantically significant. If you write Python, it's helpful to have an editor that makes the difference between tabs and spaces visible....I do this for any and every language. Mixing tabs and spaces always sucks.
In the sense that a programming language is not only made to be parsed by a computer, but also read back by a human.
If we ever move beyond using text files for storing code, we could eliminate formatting differences entirely... but efforts in that direction have run into many issues in the past.
gofmt is still optional. Python significant white spaces are not.
This is not the case.
if (ptr) call_oldschool_thingy(ptr); if (image) foo_release(image);
if (label) foo_release(label);
if (data) foo_buffer_destroy(data);
if (window) foo_window_destroy(window);
It's easier to see that all objects are being cleaned up when each occupies just one line, as that typically matches the look of the initialization: window = foo_window_create();
data = foo_buffer_create(1, 2, 3);
label = foo_label_create(window);
image = foo_image_create(window);The second example is missing error checking. So the real code isn't that nice.
My point is that C shouldn't look like Python. Small amount of functionality should be written unambiguously and take a lot of space if necessary. Because of the nature of C, it needs a lot boilerplate, and will take a lot of screen space anyway, but that is not a problem, as we are not coding on paper.
image ? foo_release(image) : 0;Any C programmer will recognize what (void)0 means, do nothing.
I find the single line "if" statement without braces to be clearer and simpler than ternary with a (void) expression, and don't think the downsides are significant. It breaks if you were to add another statement after the semicolon on the same line, but I think that should almost always be avoided anyway.
I do find it interesting that others prefer two-line without braces over the single line approach. I find this one to be more dangerous than the single line. Possibly because with line-oriented debuggers it can be hard to set the right breakpoint?
It's quite possible that others are downvoting because they think you are trolling, and that no one would actually believe the ternary operator to be clearer. I wondered also about your defense of Allman braces, which I didn't downvote because I think it's a good example of how different the others's views can be on what seems obvious. While I think (some of) your views are in the (very small) minority, please keep posting them!
if (ptr) { call_oldschool_thingy(ptr); }IMHO there should be a -W to enforce this so those of us with -Werror on can catch it and burn it with fire.
Here at Google the style guide requires block-parens always.
I got used to this quite a bit and these days if I write code outside the project I work on, I d sometimes omit the block-parens, but I always add extra indentation to ensure the condition is visually well-separated, e.g.:
if (condition1 || condition2) execute_foo1(with_bar);
if (condition3) exectute_foo2(); if ptr { call_oldschool_thingy(ptr) }
(Keystroke count isn't an important metric for me, but apparently very important to some people.)Now if only Rust supported the elision of ; ... (Yeah, I know that they have a reason to not do that, but I don't buy it.)
Meeting snippets of code like that when debugging is a constant source of frustration for me, because I have to stop what I was doing, edit the code, rebuild, then get back to where I was. Particularly galling when the code in question is in a commonly-included header, and the subsequent build takes several minutes, and I was on a particularly productive-looking trail.
(The last project I worked on solved (?) this problem by performing so shamefully poorly in an unoptimised build that it effectively didn't work. So you had to debug the optimised build. And so single-stepping at the source level just didn't work properly anyway.)
>I've never met a C or C++ debugger that handled this case nicely, unfortunately.
Apparently you never use Visual Studio. It can highlight a portion of the statement on each step (at least it used to)In C++ optimized builds, you might be jumping back and forth between lines due to the compiler re-ordering instructions, and there isn't an easy way to get back code that's in-order.
The scheme works so well that people will often go months into their Haskell education before they encounter code with explicit braces and semicolons.
And mandatory seat belt use is foolish, bike helmets are for wimps, and blade guards on saws are a waste of space and money.
Just use those tools responsibly :P
if (a)
...
else ...
But for some reason I find the below _very_ frustrating. It feels misleading and I find it to be very, very ugly.if (a)
...
else { /* Multi line block */
}I've seen
if (a) thing;
but never with an else, and certainly never with an else that has a multi-line block. That's definitely somethign I'd call out in a CR.
I'd rather a compiler forces me to put braces around everything than let people have the opportunity to do something like the latter from my original comment.
The else is executed if there is no error, in my style at least, so naturally it will contain more logic.
This is also one of the reasons I like Racket: there's no such thing as ambiguous block delimitation. Also, everything-is-an-expression is very useful.
What's frustrating is that K&R still has a lot of example code like that as well. It would be wonderful to see a 3rd edition even if it do nothing but change its code to use braces.