Persistent list

Jonathan M Davis via Digitalmars-d digitalmars-d at
Sat Nov 14 18:49:47 PST 2015

On Saturday, 14 November 2015 at 23:20:08 UTC, Andrei 
Alexandrescu wrote:
> On 11/14/15 5:49 PM, Timon Gehr wrote:
>> It's supposed to guarantee that the given reference is not 
>> used to
>> transitively mutate the object. The casts violate this.
> I think that semantics needs to change. Specifically, either we 
> add a @mutable attribute (which means const doesn't apply to 
> fields marked as such and immutable objects cannot be created); 
> or we could just decree that if a const object originates in a 
> mutable object, casts should be well-defined. -- Andrei

Either way, we'd be throwing away the idea that const is physical 
const and provides actual guarantees against mutation via const 
references. We'd essentially be going the route of having C++'s 
const except that it's transitive, which is a definite loss IMHO, 
but at the same time, with D's const, you frequently have to give 
up on using const, because physical const is so restrictive as to 
be unusable in many cases.

I honestly don't know if it's better to just say that you can't 
use const if you want to do something like reference counting or 
using an allocator or to gut the guarantees that D's const 
provides. Ideally, we'd keep the guarantees, but they often seem 
to end up being completely impractical in practice. And they 
don't jive at all with the recent push to support RC.

That being said, if we are going to make a change like this, I'm 
not sure if we even _can_ do it. immutable throws a serious 
wrench in any attempt have something like C++'s const in D.

As it stands, the only thing that really ensures that immutable 
objects aren't mutated is the type system. As I understand it, if 
an immutable object gets put into ROM (or memory that's being 
treated as ROM), then mutating it will cause a segfault, but the 
only case where that might happen right now AFAIK is if the 
object was created at compile time and stored as part of the 
program's data. Certainly, any immutable objects created at 
runtime are only protected from mutation by the type system. So, 
even if the compiler makes _zero_ assumptions based on const, 
casting away const and mutating is very dangerous, because you 
risk mutating an immutable object and violating all of the 
guarantees associated with that. The only time that casting away 
const and mutating could work would be in cases where you could 
somehow guarantee that the object you're mutating is actually a 
mutable variable underneath the hood. That would be possible in a 
restricted setting, but in a large program or in a public API, 
it's a lot less likely that you can guarantee that the object 
isn't actually immutable. There would have to be some way for the 
type system to guarantee that the object isn't actually immutable 
- which either means making it so that the type in question can't 
be immutable for some reason or having an attribute other than 
const for non-physical const.

Your @mutable suggestion/proposal does step in that direction by 
basically making it so that a const type which contains a 
@mutable member isn't really const. It's some other attribute 
that's not explicitly named (cpp_const, logical_const, 
@mutable_const, or whatever we'd want to call it). And that seems 
like it would work to a point. It would even allow for implicit 
casts instead of explicit ones and make the whole thing far safer 
in general than simply allowing arbitrary casting would. However, 
@mutable still isn't an attribute on the type. It's an attribute 
on a member. So, as soon as you have an opaque pointer or a base 
class reference, the compiler doesn't know that the object is 
actually @mutable_const. So, it can't know that it's not legit to 
have the object be immutable. Now, the compiler would have to 
know that when the object is created, and presumably an 
@mutable_const derived class couldn't convert to an immutable 
base class, so maybe this would actually work, but it seems like 
we're at serious risk of a loophole if we're not really careful 
here. It feels like each time work through this I flip-flop as to 
whether I think that it can work or not.

And of course, even if we do make @mutable work, it would 
basically mean that const doesn't necessarily guarantee much of 
anything anymore other than preventing accidental mutation, since 
unless the compiler can guarantee that no @mutable_const is 
involved, it can't assume much of anything about const (though 
what it can assume about const is already pretty limited - 
particularly when pure isn't involved), and programmers can't 
assume that a const object will really not be mutated by const 
member functions (though in practice, it's unlikely that anyone 
is going to slap @mutable on everything). But even then, we'd 
still be ahead of C++'s const if we have transitivity and 
disallow casting away const to mutate.

I'm torn on the whole thing. On the one hand, I think that D's 
guarantees with physical const have been great. On the other 
hand, too much stuff doesn't work with it. And system programming 
stuff like ref-counting, mutexes, and allocators definitely don't 
work with it.

- Jonathan M Davis

More information about the Digitalmars-d mailing list