void up_front_decls()
{
float some_var;
int another_var;
some_var = get_some_var();
do_some_calculations(some_var);
maybe_something_else(&some_var);
some_var = get_another_var();
do_some_other_calculations(another_var);
blah_blah_already_broken();
}
void as_needed_decls()
{
float some_var = get_some_var();
do_some_calculations(some_var);
maybe_something_else(&some_var);
int some_var = get_another_var();
// compile-time error
// ...
}
Also: void poor_style()
{
up_front declarations;
also encourage;
this_ridiculous *block_style;
that_is a_royal_pain;
to maintain;
because_some_long_type inevitably;
screws_it up;
}1. It wastes my time. Sure, I could probably set up my editor to fix this, but I shouldn't have to do so to satisfy someone else's pointless indentation fetish. I've personally never worked on a team where this was an accepted, general guideline. It was always just one guy who wanted this, and did it to every function he touched, adding maintenance headaches for everyone else (until/unless other people finally told him to stop).
2. It messes up diffs. Now instead of one line showing up in the diff, the entire block is often different. And yes, most diff tools have options to hide whitespace differences. Again, though, this adds overhead to everyone who doesn't want this block style. I'd rather not hide whitespace differences, because if someone has added a bunch of inappropriate whitespace (or mangled the block while trying to reformat it to include their new variable), I want to know about it during the code review so I can tell them to fix it then rather than finding it later when I'm editing the file.
3. It doesn't actually help anything. Yes, you get a nice column that shows you all the variable names. What good is that, though? Unless you're putting everything at the top of the function (which has its own set of problems), you're not really getting anything useful from this except maybe prettier code (arguable), because at a glance you still don't really get know all the in-scope variables (not to mention file-scope variables). Moreover, you actually lose something valuable with this style, because now it's harder to determine a variable's type. You're trying to scan left from the name across some indeterminate amount of whitespace to match with the type. This is not typically easy to do, which is why column-oriented data is typically displayed with alternating background colors on each row.
:Tab /\S\s\zs[ ]\S*
Explanation: \S\s* finds a non whitespace character followed by as many whitespace characters as possible. This brings us to the beginning of the variable name. We then use \zs which says that the "found" area should only begin here.
Since we want the * in block_style to be attached to the indented word but not before the variable name, we match either * or space followed by a non-whitespace character to symbolize the beginning of the word. End result:
void poor_style()
{
up_front declarations;
also encourage;
this_ridiculous *block_style;
that_is a_royal_pain;
to maintain;
because_some_long_type inevitably;
screws_it up;
} for (int i = 0; i < len; ++i) { ... }
vs. int i;
// Half a dozen lines
for (i = 0; i < len; ++i) { ... }
makes a big difference to me.People make mistakes. Practices should be built around this fact, not built assuming people could be perfect if they just tried a little harder.
With one caveat: Heavy constructor/destructor use requires it.
Not sure what you mean about "heavy constructor/destructor use" requiring this style.
If your function is five pages long, and in the fifth page you can't remember what's in scope and you have to reread through the entire function above, it might seem that having all variable declarations at the top would help, because you'd only have one place to look at. But the real problem there is that the function is too long, and it should be refactored instead.
I most certainly am const pedantic as well, and I was back when I worked on this project, too -- quite a few of the "inconsequential" lines I checked in were simply moving a variable declaration down to where it was initialized, and adding 'const'. I found the resulting code much easier to read.
If instead, a variable is assigned to only when it is defined, you're moving (in a small way) towards functional programming.
Also, I often use scope just control the lifetime of a resource. These look like meaningless braces in the middle of a function to the uninitiated. It's RAII.
You can't do that unless you look at the assembly output. While there may have once been a time in history where "locally-scoped variable == entry on stack", those days are long gone. Any decently smart compiler (i.e. GCC and LLVM) will use registers in preference to the stack, and will collapse local variables whose lifetimes do not overlap into a single storage location.
const int x = foo();
// ...
const int y = bar(x);
and also have your variables all declared at the top.In C++ I'm a const nazi and declare where used to facilitate it, but if I'm writing C that targets the MSVC compiler (C89) where all variables have to be collected at the top of the inner scope I'll relax this as much as I have to.