Persistent list
Jonathan M Davis via Digitalmars-d
digitalmars-d at puremagic.com
Sun Nov 15 21:31:02 PST 2015
On Sunday, 15 November 2015 at 19:57:12 UTC, Andrei Alexandrescu
wrote:
> On 11/15/2015 01:50 PM, Jonathan M Davis wrote:
>> On Sunday, 15 November 2015 at 18:09:15 UTC, Andrei
>> Alexandrescu wrote:
>>> On 11/15/2015 01:00 PM, Jonathan M Davis wrote:
>>>> Basically, we have to decide between having physical const
>>>> with the
>>>> guarantees that it provides
>>>
>>> We have that - it's immutable. -- Andrei
>>
>> Yes and no. As it stands, I can know that
>>
>> const foo = getFoo();
>> foo.bar();
>>
>> won't mutate foo unless I have another, mutable reference to
>> foo
>> somewhere that bar somehow accessed.
>
> That is an illusion, and we need to internalize that. Consider:
>
> // inside some module
> struct T
> {
> int[] data;
> void bar()
> {
> // look, ma, no hands
> g_data[1]++;
> }
> }
> static int[] g_data;
> const(T) getFoo()
> {
> T result;
> result.data = g_data = [1, 2, 3];
> return result;
> }
>
> In other words, you truly need access to the implementation of
> getFoo() in order to claim anything about the changeability of
> stuff. Note that I could even afford to have getFoo() return
> const, so no need for the caller to make it so!
Which is why I brought up pure. If either getFoo or bar is pure,
then your backdoor doesn't work. Yes, without pure, globals work
as a backdoor, but technically, they do that with immutable too,
since you can put the entire state of the object outside of the
object using globals.
> With immutable, it's all cool. Immutable data is truly
> immutable, and that can be counted on. But const, even today,
> cannot be assumed to be as strong.
No, const is not as strong as immutable. But my point is that
as-is const still provides some guarantees about physical
constness. And particularly when it's combined with pure, there
are a lot of cases where you can rely on a const object not being
mutated unless the programmer violates the type system. Contrast
that with C++ where pretty much any function could choose to cast
away const and mutate an object, making the const attribute
essentially meaningless in principle. In practice, programmers
are obviously better behaved than that, but it means that in D
right now, const does provide actual compiler guarantees (even if
they're not as strong as those for immutable), whereas in C++ it
really only prevents accidental mutation.
If we go the route of making casting away const and mutating
defined behavior (and possible adding something like @mutable),
then what we'll end up with is a transitive version of C++'s
const, and that definitely provides worse guarantees than we have
now. So, we would be losing something if we made that change.
That being said, const as-is _is_ very restrictive, and a number
of idioms are completely incompatible with it, and that sucks.
But we've known that for some time, and the answer has generally
been to either not use those idioms or to not use const - which
unfortunately does mean that const often can't be used (and a
container that needs to do fancy stuff with its internals is
probably a prime place where it can't be used).
So, I'm not necessarily against changing how const works. It _is_
restrictive to the point of being impractical in a lot of code.
But if we make such a change, we _will_ be losing out on the kind
of compiler guarantees that Walter has been harping on for ages -
how C++'s const is pretty much useless since it doesn't really
guarantee anything, whereas D's const does provide compiler
guarantees because it can't be legally cast away and mutated. And
you don't seem to see that (at least based on what you've been
saying).
There is a tradeoff to be made here. We've been choosing one side
of that tradeoff for years now - the side that C++ didn't choose.
Maybe we made the wrong choice and should switch sides. But it is
a tradeoff, not a clear-cut decision.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list