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

Reply via email to