The case against local variables basically boils down to:
1. "I don't need the compiler to avoid writing bugs"
> I don’t need a keyword just to tell me that a variable isn’t modified during its lifetime. I can see that fact at a glance [...]
Not terribly convincing.
2. might inhibit automatic move of return value
This is an edge case that does not affect correctness, only performance, and rarely pops up unless the code has other, worse problems.
(also, when it does happen, it is trivially found by static analysis tools, and clang-tidy will point it out to you)
> But suppose there were many more lines of code interspersed between the [definition of fullName] and the final call to e->setName(fullName). That call makes an unnecessary copy. The programmer might try to fix it by writing e->setName(std::move(fullName))… but guess what? fullName was const-qualified, so the move does nothing!
If there are "many more lines of code interspersed between the variable definitions and the final call", this implies that fullName is used somewhere between its definition and the final call (it makes no sense to declare fullName before it is required).
But after fullName is moved from, it should not be referenced again. This means that rearranging the function (so that fullName is used after the move) would introduce a correctness bug.
This is in itself a bad situation which should be avoided by refactoring, so it's not a great example (it's also not great that the actual example is not written out as code, merely handwaved). But this is actually an example where defaulting to const could be at least a bit helpful, because doing so makes all non-const variables stand out and warrant extra attention.
> I don’t need a keyword just to tell me that a variable isn’t modified during its lifetime.
I agree that this isn't very well argued, and variable re-use is a common source of bugs – especially variables that are used several times in a single function for different purposes.
On a similar point, Java has `final` instead of `const` and it does apply to local variables, including to guarantee that a variable is not only not modified, but set exactly once. Something like this:
final String foo;
if (condition) {
foo = someValue();
} else {
foo = otherValue();
}
Omitting any of the assignments leads to a compilation error. It works with complex if conditions with multiple branches, and even with `switch`. If a branch throws an exception, that's also acceptable as the variable is guaranteed not to be used below.
I find it pretty useful; doesn't C++ provide a similar construct?
For the most part I agree with the article, but yes, for long functions I will often const locals that I want to make sure they stay constant (i.e. there is some cross variable invariant that I want to make sure always hold). I won't bother for functions of less of 10 lines (but it is not a rule and I wouldn't want it to be enforced).
I also see no issues in consting members of classes that don't have value semantics.
1. "I don't need the compiler to avoid writing bugs"
> I don’t need a keyword just to tell me that a variable isn’t modified during its lifetime. I can see that fact at a glance [...]
Not terribly convincing.
2. might inhibit automatic move of return value
This is an edge case that does not affect correctness, only performance, and rarely pops up unless the code has other, worse problems.
(also, when it does happen, it is trivially found by static analysis tools, and clang-tidy will point it out to you)
> But suppose there were many more lines of code interspersed between the [definition of fullName] and the final call to e->setName(fullName). That call makes an unnecessary copy. The programmer might try to fix it by writing e->setName(std::move(fullName))… but guess what? fullName was const-qualified, so the move does nothing!
If there are "many more lines of code interspersed between the variable definitions and the final call", this implies that fullName is used somewhere between its definition and the final call (it makes no sense to declare fullName before it is required).
But after fullName is moved from, it should not be referenced again. This means that rearranging the function (so that fullName is used after the move) would introduce a correctness bug.
This is in itself a bad situation which should be avoided by refactoring, so it's not a great example (it's also not great that the actual example is not written out as code, merely handwaved). But this is actually an example where defaulting to const could be at least a bit helpful, because doing so makes all non-const variables stand out and warrant extra attention.