Re: Variables in for loop (style issue)
James Dennett wrote:
Walter Bright wrote:
My post about foreach was in the context of loop idioms, loop
invariants, and loop techniques, and I don't believe that C++ const
plays a useful role in such (as explained), so C++ isn't better in that
regard.
mytype const end = expression();
expresses very nicely in C++ (maybe in D, I don't know) the
fact that end will *not* change in any valid program.
That's true. This is an example of the top level, or "storage class
const" meaning of C++, as opposed to the "type modifier const" meaning.
In my discussions of the utility of const, I've usually tried to be
careful to distinguish the two. In C++, the "storage class const"
actually is guaranteed to be constant by the language specification, and
so is useful. D also has const as a storage class, with equal utility.
Changing
it so that it is not const, but merely a reference or pointer
to const is a fundamental change.
Yes, you are quite correct.
Let's not pretend that const
is not useful just because something *being* const is a much
stronger statement than saying that we have a pointer-to-const
or reference-to-const.
Again I agree, and I have tried (and obviously failed) to properly
distinguish between the two C++ uses of const.
Sure, pointer-to-const doesn't say much
unless we (and/or an optimizer) know that there's not aliasing.
An optimizer can assume absolutely that end is only used as
a const object; any thing else is undefined behavior.
That is correct. I should add, however, that data flow analysis is
pretty good at determining simple local variable loop invariants without
the need for the storage class const, so its incremental utility for
loop optimizations is slight.
Most of the C++ programmers I've seen don't seem to find this
hard to understand. I'm not suggesting that you don't
understand it; I suspect your understanding of the language
rules is perfectly good enough to understand it. I just find
it odd that you bring it up; it seems to me to be a straw man.
But maybe there's some deeper point that you're alluding to?
My deeper point is that the "type modifier const" meaning of C++ const
has little to no utility. A corollary to that is the notion of "const
correctness", which relies on the type modifier const, therefore also
holds little utility.
In fact, it's arguable that const as a type modifier may be
worse than no const at all, since nearly all I talk to about it are
surprised to find out that const offers no guarantee of constancy. It
leads people into a false sense of how their programs work.
How about the many, many people out there who find that
const as it exists in C++ is close to a design concept
that is useful (to human readers and writers) when expressed
in code?
That is the self-documenting aspect of const, a point which I addressed
in another recent post in this thread.
That it can occasionally help an optimizer is a
side-issue; that it doesn't always do so is worth mentioning
once, in passing.
OK, you say it "occasionally" can help an optimizer. When can const as
type modifier (not as storage class) help an optimizer?
const-qualified member functions document
something very useful, and it's only a little extra work to
bridge the (often small) gap between logical and physical
constness.
An optimizer must take the most adverse view possible of the meaning of
code consistent with the language rules. And that view of type modifier
const is that it has no more semantic meaning than /*const*/. Being a
compiler implementor, I admit I tend to adopt the viewpoint of a
compiler when looking at code. But I should also think that if one is
working on critical code, or reviewing critical code for robustness and
reliability, one must also take the most adverse view possible, and so
cannot rely on type modifier const.
I've worked in languages without const, and I find that many
of those using them tend to come up with poor/unclear designs
which consideration of const-correctness would have avoided.
That is an excellent point. I am very much interested in language design
issues that encourage (i.e. make easy) better code while discouraging
(i.e. require extra work) poor code.
One of my issues with C++ const is that it's a lot of extra work to take
working code, and then make it const-correct. Const-correct code tends
to be littered with here a const, there a const, everywhere a const
const. Given the observation (unencumbered by evidence, so don't ask(!))
that 90% of the time one is merely referencing data, and only 10% of the
time modifying it, doesn't this seem backwards? Shouldn't const be the
*default*, and things that are expected to change have to be marked with
"mutable"?
That would make const-correctness be more of a natural coding style,
rather than an extra layer added on with tedious extra effort.
Particularly in languages which emphasize reference semantics,
knowing that an object can't be changed via a reference is a
significant help; sharing immutable objects is clearly much
more straightforward than safely sharing mutable ones. Good
naming can go some way towards limiting the damage, but C++
does help by capturing a decent approximation to logical
const-ness in a way that the compiler can enforce.
I don't disagree with the goal. But don't you want for more than just a
decent approximation? C++ has so many such approximations (such as
for_each and std::string). Why not aim for something that hits the mark
squarely? (I don't have such a solution yet for const, but hope to find it.)
(Yes, I pepper my parameters and local variables with "final"
when writing in Java. It's not as good as const, as having
a "final MyType p" doesn't ensure that the MyType object
isn't changed, but it's better than nothing.)
C++ "const" doesn't ensure it, either, if MyType is a reference type. As
I explained in another recent post here, a const T& can be legally
changed via that reference.
In summary: const is great for writing correct, clear code.
It's less help to the optimizer than it is to the programmer.
That said, D will probably get some notion of const. But it will be one
that works, i.e. can be relied upon by both the programmer and the
optimizer.
I don't have a problem with relying on const in my C++ code.
It always obeys the language rules, they're not complicated.
The only source of confusion you've raised is the (novice?)
error of thinking that seeing
mytype const & r
or
mytype const * r
means that the object pointed to by r can't change.
You're obviously well aware of the issue here. But it surely is not a
novice issue. I regularly run into serious, professional C++ experts who
are mistaken about it.
I don't
find that error to be common in practice, but your experience
may be different. C++ is a widely used language, and all of
us cover different subsets of its use.
I ran smack into the issue when confronted by bug reports of "this works
unoptimized, but fails when optimized." I cannot change the language
spec, nor programmers, nor can a viable compiler only work on a subset
of C++. What one must do is implement C++ as it is, and as it is, const
as type modifier doesn't help code optimization. To implement otherwise
breaks existing, established, legal C++ code.
-Walter Bright
www.digitalmars.com C, C++, D programming language compilers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]