C++ : Const correctness


PART 10


Q41: What is `const correctness'?
A: A program is `const correct' if it never mutates a constant object.  This is
achieved by using the keyword `const'.  Ex: if you pass a String to a function
`f()', and you wish to prohibit `f()' from modifying the original String, you
can either pass by value:	void  f(      String  s   )  { /*...*/ }
or by constant reference:	void  f(const String& s   )  { /*...*/ }
or by constant pointer:		void  f(const String* sptr)  { /*...*/ }
but *not* by non-const ref:	void  f(      String& s   )  { /*...*/ }
*nor* by non-const pointer:	void  f(      String* sptr)  { /*...*/ }

Attempted changes to `s' within a fn that takes a `const String&' are flagged
as compile-time errors; neither run-time space nor speed is degraded.



Q42: Is `const correctness' a good goal?
A: Declaring the `constness' of a parameter is just another form of type
safety.  It is almost as if a constant String, for example, `lost' its various
mutative operations.  If you find type safety helps you get systems correct
(especially large systems), you'll find const correctness helps also.

Short answer: yes, const correctness is a good goal.



Q43: Is `const correctness' tedious?
A: Type safety requires you to annotate your code with type information.  In
theory, expressing this type information isn't necessary -- witness untyped
languages as an example of this.  However in practice, programmers often know
in their heads a lot of interesting information about their code, so type
safety (and, by extension, const correctness) merely provide structured ways to
get this information into their keyboards.

Short answer: yes, const correctness is tedious.



Q44: Should I try to get things const correct `sooner' or `later'?
A: Back-patching const correctness is *very* expensive.  Every `const' you add
`over here' requires you to add four more `over there'.  The snowball effect is
magnificent -- unless you have to pay for it.  Long about the middle of the
process, someone stumbles on a function that needs to be const but can't be
const, and then they know why their system wasn't functioning correctly all
along.  This is the benefit of const correctness, but it should be installed
from the beginning.

Short answer: CONST CORRECTNESS SHOULD NOT BE DONE RETROACTIVELY!!



Q45: What is a `const member function'?

A: A const member function is a promise to the caller not to change the object.
Put the word `const' after the member function's signature; ex:
	class X {
	  //...
	  void f() const;
	};

Some programmers feel this should be a signal to the compiler that the raw bits
of the object's `struct' aren't going to change, others feel it means the
*abstract* (client-visible) state of the object isn't going to change.  C++
compilers aren't allowed to assume the bitwise const, since a non-const alias
could exist which could modify the state of the object (gluing a `const' ptr to
an object doesn't promise the object won't change; it only promises that the
object won't change **via that pointer**).

I talked to Jonathan Shopiro at the C++AtWork conference, and he confirmed that
the above view has been ratified by the ANSI-C++ standards board.  This doesn't
make it a `perfect' view, but it will make it `the standard' view.

See the next few questions for more.



Q46: What is an `inspector'?  What is a `mutator'?
A: An inspector inspects and a mutator mutates.  These different categories of
member fns are distinguished by whether the member fn is `const' or not.



Q47: What is `casting away const in an inspector' and why is it legal?
A: In current C++, const member fns are allowed to `cast away the const-ness of
the "this" ptr'.  Programmers use (some say `misuse') this to tickle internally
used counters, cache values, or some other non-client-visible change.  Since
C++ allows you to use const member fns to indicate the abstract/meaning-wise
state of the object doesn't change (as opposed to the concrete/bit-wise state),
the `meaning' of the object shouldn't change during a const member fn.

Those who believe `const' member fns shouldn't be allowed to change the bits of
the struct itself call the `abstract const' view `Humpty Dumpty const' (Humpty
Dumpty said that words mean what he wants them to mean).  The response is that
a class' public interface *should* mean exactly what the class designer wants
it to mean, in Humpty Dumpty's words, `nothing more and nothing less'.  If the
class designer says that accessing the length of a List doesn't change the
List, then one can access the length of a `const' List (even though the `len()'
member fn may internally cache the length for future accesses).

Some proposals are before the ANSI/ISO C++ standards bodies to provide syntax
that allows individual data members to be designated as `can be modified in a
const member fn' using a prefix such as `~const'.  This would blend the best of
the `give the compiler a chance to cache data across a const member fn', but
only if aliasing can be solved (see next question).



Q48: But doesn't `cast away const' mean lost optimization opportunities?
A: If the object is constructed in the scope of the const member fn invocation,
and if all the non-const member function invocations between the object's
construction and the const member fn invocation are statically bound, and if
every one of these invocations is also `inline'd, and if the ctor itself is
`inline', and if any member fns the ctor calls are inline, then the answer is
`Yes, the soon-to-be-standard interpretation of the language would prohibit a
very smart compiler from detecting the above scenario, and the register cache
would be unnecessarily flushed'.  The reader should judge whether the above
scenario is common enough to warrant a language change which would break
existing code.