Persistent list
Jonathan M Davis via Digitalmars-d
digitalmars-d at puremagic.com
Fri Nov 13 19:57:47 PST 2015
On Friday, 13 November 2015 at 23:10:04 UTC, Andrei Alexandrescu
wrote:
> * Lines 26-29: The allocator is fundamentally a mutable part of
> the container. This is an insufficiency of our type system - we
> can't say "this object may be constant, but this reference is
> to a mutable part of it". We can't explain that necessity out
> of existence, and List is part of the proof. So we need to make
> that cast legal.
>
> One simple solution is to simply allow the cast. One more
> involved is to define an attribute @mutable with the following
> rules: (a) @mutable data is not affected by const; (b) if a
> type T contains transitively any @mutable member, immutable(T)
> is illegal. That would allow us to not need a cast in line 28.
The problem (at least with the current cast) is that D's const is
supposed to be physical const, not logical const, and treating
any of its parts internally as mutable violates that. When the
const object could actually be immutable underneath, we really
have no choice about that, because immutable needs to be physical
const to do what it does. With immutable out of the picture, it
becomes a more interesting question.
As it stands, the compiler can assume that a const object doesn't
mutate if it knows that no other references to that data could
have mutated it. In theory that's worth something but in practice
is probably pretty much useless, since it's likely to help only
when pure member functions are called in succession. But if we
allow @mutable, then we'll have to ensure that the compiler never
does any optimizations based on const when @mutable is involved
(and possibly make it never make optimizations based on const
anywhere since stuff like pointers and classes are can hide the
fact that @mutable is involved).
The bigger problem is that it undermines the guarantee that const
objects can't be mutated via a const reference, since as soon as
a member variable is @mutable, that's circumvented. As long as
casting away const and mutating is still undefined behavior, then
it's only a matter of finding @mutable members, but it basically
means that we're allowing D's const to go from physical to const
to logical const (where the mutation isn't even actually
guaranteed to follow the rules of logical const, since it's the
programmer that controls it), and that's not a small thing,
particularly in light of how much Walter prizes the compiler
guarantees that physical const provides (and I agree that there's
real value there).
Now, as it stands, D's const is so restrictive that certain
idioms are just plain impossible with it. Ref-counting is the
prime example, and your predicament with the container highlights
another. And aside from immutable, we _can_ choose to change how
D's const works so that it has backdoors like @mutable. And given
how many D programmers seem to have pretty much decided that
const is useless and shouldn't be used precisely because it's too
restrictive, that may be exactly what we need to do. But
regardless, we _do_ need to do it in a way that allows const to
work properly with immutable, and disallowing immutable with
@mutable and ensuring that the compiler doesn't make assumptions
about const that don't jive with @mutable when it's possible that
@mutable is involved should then make it possible for us to make
a change to const to make it less restrictive.
So, while I don't really like the idea of putting a backdoor in
const, I think that it's clear that we're either going to have to
put in that backdoor, or we're going to have to disallow idioms
like what you're trying to do with the allocator in this
container.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list