D const design rationale

Bill Baxter dnewsgroup at billbaxter.com
Fri Jun 22 13:22:56 PDT 2007


Walter Bright wrote:
> http://www.digitalmars.com/d/const.html

Very nice read.

But I have a few nitpicks too.  :-)

"""
Which brings up another aspect of const in D - it's transitive. Const in 
C++ is not transitive, which means one can have a pointer to const 
pointer to mutable int. To declare a variable that is const at each 
level, one must write:

int const *const *const *p;   // C++

The const is left associative, so the declaration is a pointer to const 
pointer to const pointer to const int. Const being transitive in D means 
that every reference reachable through the const is also const. An 
entire logical region of an application can be protected by placing only 
one qualifier. To reflect that, the syntax is different, using 
constructor-like notation:

const(int **)* p;	// D

Here the const applies to the part of the type that is in parentheses.
"""

The way these two examples come one right after the other it leads one 
to expect that the D example is going to show the D equivalent of the 
C++ code.  But I don't think that's what it's doing.  I would suggest 
first showing the D version of the C++ snippet (which is just const 
int***p -- right?).  That gives people a chance to say "ooh ah D is so 
much simpler".  Then follow up by saying "what if we instead want part 
of that to be modifiable?  And give the const(int**)* p example (and 
maybe a C++ version of that too).  Also the way it is it doesn't explain 
sufficiently what "applies to the part in parenthesis" means.  Being 
explicit about what's modifiable there would be helpful.  Maybe remind 
people to read decls from right to left and spell it out "this is a 
mutable pointer to const pointer to const pointer"

"""
But there is a need for a constant declaration referencing a mutable type.
"""
This transition could be clearer.  This line comes shortly after 
introducing 'invariant', so it sounds like you're still talking about a 
nuance of invariant here rather than moving on to the last of the big 
three const-related keywords.  Maybe say something like "Finally, there 
is also a need ..."

Also in the discussion of final, the word that always comes to my mind 
is 'binding'.  It's the binding of the variable name to its value that's 
final.   You say, "A final declaration, once it is set by its 
initializer or constructor, cannot ever change its value for its 
lifetime."  which to me is kind of vague.  I not sure what it means that 
"a declaration cannot change its value".  Does a declaration even have a 
value?  "I'm setting this declaration to 5" -- seems like unusual 
terminology to me.


This is more of a question than a suggestion, but here:
"""
Since a final declaration cannot change its value, it is by nature 
invariant, and the address of it will become a pointer to an invariant:
"""

That means this is ok:
   int x,y;
   final int* p = &x;
   p = &y;		// error, p is final
   *p = 3;		// ok, *p is mutable

But if I take &p then I lose the ability to indirectly set x?
   **(&p) = 5;           // error *(&p) not same type as p!


Finally:
"""
Like C++, D allows the casting away of constness and invariantness. 
Unlike C++, if the programmer then subverts the const or invariant 
guarantee and changes the underlying data, then undefined behavior results.
"""

This seems like kind of a weak ending.
Lack of being able to trust const due to casts is listed as one of the 
big problems with C++'s const.  Yet in the end it reads like D does 
*less* than C++ here.  Not only can you cast at will, you can't even be 
sure it will work.

Maybe it's just the weak statement "undefined behavior results" that 
bothers me.  It makes it sound like it just happens -- because it was 
too difficult to implement or something --  rather than it being a 
proactive component of D's design.  Something like this might read better:

"""
Unlike C++, D specifies that subversion of the const or invariant 
guarantee will result in undefined behavior.  Casting away const is safe 
only if the data referenced is truly not modified.  Of course even in 
C++, casting away const in order to modify data is usually not /safe/, 
merely well defined.  D allows the compiler to make optimizations which 
assume const data will not change, whereas C++ requires compilers to 
assume that it always changes, despite being const.
"""


--bb



More information about the Digitalmars-d mailing list