What guarantees does D 'const' provide, compared to C++?
Jonathan M Davis
jmdavisProg at gmx.com
Thu Aug 16 17:10:40 PDT 2012
On Friday, August 17, 2012 01:35:46 Mehrdad wrote:
> > The main thing given is transitivity.
>
> Sure, but what kind of an advantage does that provide compared to
> C++?
> (As in, a code sample would be awesome -- it's so much easier to
> explain with an example to compare, rather than with words.)
In C++, if you have
const vector<T*>& getStuff() const;
which returns a member variable, then as long as const isn't cast away, you
know that the container itself won't have any elements added or removed from
it, but you have _zero_ guarantees about the elements themselves. In contrast,
in D,
const ref Array!(T*) getStuff() const;
you would _know_ that not only is the container not altered, but you know that
the elements aren't altered either - or anything which the elements point to.
And since casting away const and mutating a variable is undefined behavior, and
there is no mutable, you don't have to worry about the state of the object
changing at all unless it's shared (since another thread could alter it
through a non-const reference) or you can somehow get another, non-const
reference to it in the current thread. So, it becomes trivial for a class or
struct to guarantee that nothing can change the member variables that it
returns from const functions.
> > The compiler will guarantee you aren't changing data that is
> > const.
>
> Right, but it's the same with C++, right? Where's the difference?
C++ makes no such guarantees, because you're free to cast away const and
modifiy objects and because objects can have members marked with the mutable
keyword. All const really does in C++ is make it so that you don't
accidentally, directly modify a variable which is const. It makes _zero_
guarantees about the state of the object beyond that.
> > On the note of casting away const, I don't believe that is the
> > operation which is undefined, however modifying const is
> > undefined as it could be pointing to immutable data.
>
> Oh, then that's not what I'd understood. Seems just like C++ then.
No. Casting away const and modifying an object is well-defined in C++. The
casting is well-defined in D but not the modification. That's undefined behavior
- both because it will do nasty things if the object is actually immutable and
because D allows the compiler to assume that anything which is const is not
modified by another thread if it's not shared (the _only_ thing which could
alter that variable is another, mutable reference to the same data on the same
thread).
> > I believe there is an article which speaks to const, but the
> > inference benefits come from immutability and pure functions.
>
> Ahh, right. You need immutability and purity for const to be any
> more advantageous than in C++. It seems like it's a point worth
> emphasizing in the const article (and perhaps when explaining
> const to newbies), since people might not understand why const is
> powerful unless they actually start using immutability, too.
> (Also kind of prevents the situation where C++ users try to use
> const as logical const, without realizing that it's meant to work
> with immutability/purity instead.)
const is useful even without purity, because you _know_ that nothing which is
const can change unless you access it through a non-const reference, and
everything being thread-local by default makes it that much harder for that to
happen, allowing the compiler to more easily guarantee that a const object
isn't changed and do optimizations based on that.
Now, it _does_ get far better once purity is added into the mix, because then
neither you or the compiler has to worry about function calls altering a
variable through global variables, since they can't be accessed, making it
easier for you to understand the code and easier for the compiler to make
optimizations. But D's const by itself still allows for more optimizations
than C++'s const does.
And of course, immutable offers even better guarantees, since neither you nor
the compiler has to worry about there being mutable references to the same
data anywhere. So, it enables even better optimizations (and combined with
pure, it can even lead to whole function calls being elided).
While D's const can be too restrictive at times, I'm increasingly annoyed by
how flimsy C++'s const is in comparison. In particular, without transitivity,
putting const on a getter frequently means next to nothing.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list