Advice on coding style

Started by
45 comments, last by Hodgman 8 years, 3 months ago

I see that as a common reason given as to why you should always use braces, even for 1-liners, but TBH I've never seen that hypothetical bug happen. The missing braces in your buggy example are so painfully obvious even at a glance that the person adding the cout would have to be blind in order to forget to add the braces...

It happened to me while working in Thailand and trying to debug another person’s sprite-related code.
That was just an example, so “it’s obvious” isn’t really a rebuttal. I was trying to figure out in release-mode (no break-point support) in which of the many places it could break from several loops, and I got sloppy after the 15th time I had to put a print (loose description of actual event—numbers and motivations may have been changed to protect their identities).
Yes, it is usually obvious, which is why I only missed one spot out of 16.
But that really took a lot of my time and was simply unnecessary.
Not to mention that in 16 places I had to waste more time placing braces that should have already been there. It takes more time to re-format existing code than to code it correctly in the first place.

What is the argument for omitting braces?
Real-estate? Then why not:


if(count == students) break;

Or even better:


if(count == students) { break; }

Is it supposedly “faster to type because less typing”?
When typing braces is an automatic non-thought process, typing them always is never slower than considering whether you need them or not and omitting them accordingly.

What’s the win?


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Advertisement

if(count == students) { break; }

Yusssssss.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

There is just no excuse for it. It’s tacky, inconsistent (compared to every other place where you must use braces), and not only provides no benefit, it can harm you too.


I'm with Hodgman. I've *never* seen a braces-and-mismatched-indentation bug.

It seems like a style-specific problem to me. Match your open brace's vertical or horizontal position with your close brace and you'll always spot improper indentation.


Yes
{
}


Yes { }

NO {
}

IWillFindYouAndKillYouButAtLeastICanReadYourCode {
                                                 }

Advice on the braces will be taken to heart and corrected. I was using:

NO {

}

because I thought it saved space and looked cleaner.

So I found out the problem with the first program I just don't full understand why. While entering grades, I type "end" to make while(cin>>x) false, but somehow it messes up the next string input. So I did this and it worked:


cout << "Enter the students grades, 00 to end: ";
		
		while(cin >> x)
		{
			grades.push_back(x); 
			if(x == 00) { break; }
		}
		}

Is there a function call to purge / clear an error in the input stream? cin.clear() didn't work.

because I thought it saved space and looked cleaner.

It does.
YES {
}
But I personally really don’t care. Most companies use:
Function
{
    if() {
    }
}
Which means you have to do both anyway.


[background=#fafbfc]It seems like a style-specific problem to me. Match[/background]

your open brace's vertical or horizontal position with your close brace and you'll always spot improper indentation.
What does that have to do with anything? I literally just gave an example where I was modifying someone else’s code.
I was inserting debug prints into existing code that omitted the braces. And I was so tired of adding all the braces I eventually forgot to do it. Even if I hadn’t forgotten to do it it still wasted far too much of my time just having to add braces so that my inserted debug prints would still work properly.

Why is it that we are against singletons and globals/statics (variables and classes/member functions) because they promote the idea of the author forcing him- or her- self into having “only one” (among other reasons), but when the author says, “There will only ever be one statement after this if,” we are just like, “Yeah, whatever, sounds good”?

First-off, my example case wasn’t hypothetical—it happened to me out of exhaustion from having to spend so much time modifying so many places.
Second-off, one of my main points is about consistency. If we are going to teach people to always consider that they might want more than one of something, why would we make an exception for statements?
And why would we choose to have braces here but not there? Consistency. Either always braces or never braces. And since “never braces” is not possible, “always braces” is the only consistent pattern.

Is there a function call to purge / clear an error in the input stream? cin.clear() didn't work.

system("CLS");
Which is evil, but likely fine for your current level and task/needs.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Is there a function call to purge / clear an error in the input stream? cin.clear() didn't work.

Yes. It's in the code I showed you earlier. Look at the steps I used to clean up the stream after the comment.

You're clearing the error flags, but not removing the bad data from the stream.

Also, be advised that using 0 at the beginning of a number is the notation for octal. In the case of 00 it doesn't matter because zero is the same in any base, but 010 is 8, not 10, so watch out for that.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Most companies use [a newline for functions and same line for if]

FWIW I've never seen that style in use.

it happened to me out of exhaustion from having to spend so much time modifying so many places
That was just an example, so “it’s obvious” isn’t really a rebuttal. I was trying to figure out in release-mode (no break-point support) in which of the many places it could break from several loops, and I got sloppy after the 15th time I had to put a print (loose description of actual event—numbers and motivations may have been changed to protect their identities).
Yes, it is usually obvious, which is why I only missed one spot out of 16.
But that really took a lot of my time and was simply unnecessary.
Not to mention that in 16 places I had to waste more time placing braces that should have already been there. It takes more time to re-format existing code than to code it correctly in the first place.

As I said before, in 20 years of C++ I've not run into that bug, so the anecdote doesn't sway me tongue.png Silly bugs from being tired and making repetitive changes sloppily happen everywhere. A good static analyzer excels at pointing out those kinds of bugs smile.png
Adding braces to an un-braced line/block is one key press in my IDE.
I spend more time reading code than writing it, so that's what I'm considering here -- I'm not trying to optimize typing speed. But now you're arguing that it's too hard to press a key to add missing braces when modifying code tongue.png
Decisions based on subjective feelings cannot be correct or incorrect.

Why is it that we are against singletons and globals/statics (variables and classes/member functions) because they promote the idea of the author forcing him- or her- self into having “only one” (among other reasons), but when the author says, “There will only ever be one statement after this if,” we are just like, “Yeah, whatever, sounds good”?

Come on. That's a tad dramatic. I made you press a key, not refactor the entire code-base after performing an exhausting dependency analysis and redesigning the application's core architecture.

What is the argument for omitting braces?
Real-estate? Then why not:


if(count == students) break;
Or even better:

if(count == students) { break; }
Is it supposedly “faster to type because less typing”?
When typing braces is an automatic non-thought process, typing them always is never slower than considering whether you need them or not and omitting them accordingly.

What’s the win?

As above, I don't think there's a win in this particular part of a style debate for any side. It's purely style, to make the reader comfortable. I personally find this style comfortable to read, so that's the win. And yeah, I do use one-liners (usually without the braces) like in your first code-block there, when they happen to be the most readable option.

e.g. A random function from some personal code for allocating in a segmented stack:


u8* Scope::Alloc( uint size, uint align )
{
	for(;;) 
	{
		if( alloc->Align(align ? align : 16) )
		{
			u8* data = alloc->Alloc(size);
			if( data )
				return data;
		}
		OnOutOfMemory(align + size);
	}
}

Opening braces moved up a line -- I just don't like it. It looks sloppy and less readable to me.


u8* Scope::Alloc( uint size, uint align ) {
	while(1) {
		if( alloc->Align( align ? align : 16 ) ) {
			u8* data = alloc->Alloc( size );
			if( data ) {
				return data;
			}
		}
		OnOutOfMemory( align + size );
	}
}

Always using braces, even for one-liners, and padding out the ternary -- eh, it's ok, but looks unnecessarily bloated to me now... I find it less readable.


uint8_t* CScope::Alloc( unsigned int size, unsigned int align )
{
	align = align
	      ? align
              : 16;
	do 
	{
		if(_alloc->Align(align))
		{
			uint8_t* data = _alloc->Alloc(size);
			if(data)
			{
				return data;
			}
		}
		OnOutOfMemory( align + size );
	} while(1);
}

Maybe you want your opening braces on the same line, but also want the extra whitespace that you'd get from dedicating a line to each brace, and more! Maybe you also believe in half-tabs, and have banned ternaries and multiple exit points. Hey, I won't judge if you find this more readable. I have seen code like this before....


uint8_t* 
CScope::Alloc
( unsigned int size, 
  unsigned int align )
{
  uint8_t* data;

  if( align == 0 ) {

    align = 16;

  }

retry:

  if( m_alloc->Align(align) ) {

    data = m_alloc->Alloc(size);

    if( data )     {     goto success;    }

  }

  OnOutOfMemory( align + size );

  goto retry;

success:

  return data;

}

I find the top one the most readable. Others will disagree. That's to be expected from a stylistic choice. There's not many concrete objective arguments either way. As others have said, the most important thing is consistency, so I write in whatever style the rest of the codebase is using.
n.b. I also use u8 instead of uint8_t, and uint instead of unsigned int in that code. There's a lot of objective arguments against making your own typedefs like that, but I subjectively find them to help readability a lot. There's also 4 ways to write an infinite loop there -- I won't judge any of them, except the goto laugh.png

Personally, I hate the brace-on-the-same-line-as-the-keyword style, as I like to be able to scan vertically to pair up braces. Having the start/end braces horizontally offset robs me of that nice little sanity check. As an objective complaint, that's about as weak as the people-might-python-indent complaint though smile.png
However, in Lua for example, instead of "{" we have "then"/"do" and instead of "}" we have "end". So in a language like that, you could write:


if blah 
then
  doStuff()
end

but I do typically follow the idomatic style of:


if blah then
  doStuff()
end

...as I subjectively find that to be more readable.

This topic is closed to new replies.

Advertisement