On Mon, 09 Aug 2010 19:35:38 -0400, Jonathan M Davis
<jmdavisp...@gmail.com> wrote:
On Monday, August 09, 2010 15:01:28 Steven Schveighoffer wrote:
Then the author failed to make it const, and it's a bug in the function
definition. "Casting away const if you don't write" is crap, and should
be treated as suspiciously as code that writes to const data.
I totally agree that the author of the code screwed up. However,
sometimes you
have to deal with other people's screw ups. And unfortunately, in my
experience,
a _lot_ of programmers don't bother to write const-correct code, and it
causes
huge problems for those of us who do.
Yes, but by using such code and casting away const you are:
1) opening up your application to potential undefined behavior if the code
you are using changes in a way that actually *does* write to the object
2) opening up your *own* code to potential undefined behavior in case you
accidentally forget that you casted away const.
Casting away const is bad unless you control all the elements involved,
and I think you need to limit it to small pieces of code where you
scrutinize every aspect of it.
I think creating a Mutable wrapper for a type can potentially be an asset
if it's done correctly.
What if calculating the hash is expensive, and you know you don't have
to
recalculate it, you might cache it as a member of the class. Believe
me,
if a programmer can do it, he will. Documentation saying "don't do
this!"
isn't enough.
That's why mutable would be highly desirable, but we don't have it so
tough luck
for us on that count, I suppose. As for documentation, if the function
is const,
then no documentation is necessary. They just can't do it (not without
casting
away constness and going into undefined territory anyway).
As long as its encapsulated, I think we are ok. Note that there are other
parts of the instance that are always mutable, such as the monitor object.
Personally, I'd say tough luck to the guy who wants to cache the hash by
calculating it in toHash(). He can call some other function to cache it,
or he
could have a non-const version which caches it for cases where the
object isn't
const, or he could calculate it when something in the class changes
(which
naturally comes with its own set of pros and cons). From the perspective
of
logical constness, there is no reason why toHash() can't be const.
I've proven that logical const is doable without breaking const in a post
a couple years ago. It's just lacking the language support. I also made
an extremely complex proposal to allow specification of various levels of
const but that was rejected on account of being too complex :)
But looking at things like Rebindable, I think we should be able to make a
logical const type that allows what we need in a controlled manner.
The one thing that stumps me is why associative arrays allow for const
keys with
toHash() not being const. If I were to try and write a hashtable
implementation
myself, I'd have to cast away the constness of the keys to be able to
call
toHash() on them, which would be _really_ annoying. Maybe that's what
associative arrays are doing internally.
hehe, AA's are part of the runtime, so they manually must obey const
rules. Basically, they get a TypeInfo and a void * (which the compiler
strips of any const or type) and have to do the right thing. The
TypeInfo's getHash() function takes a void *, so no const is obeyed,
that's why it works.
Personally, I tend to be of the opinion that if a function can be const,
it
should be const. There are always exceptions of course, but generally I
think
that functions should be const when possible. It allows for writing
const-
correct code much more easily (if not just outright makes it possible),
and that
can reduce the number of mutation bugs that programmers have to deal
with.
I agree.
-Steve