Head Const

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Thu Feb 18 23:46:32 PST 2016


On Friday, 19 February 2016 at 06:39:53 UTC, Walter Bright wrote:
> On 2/18/2016 9:46 PM, Jonathan M Davis wrote:
>> On Thursday, 18 February 2016 at 22:40:32 UTC, Walter Bright 
>> wrote:
>>> On 2/18/2016 4:16 AM, Jonathan M Davis wrote:
>>>> headconst may solve the extern(C++) problem, but it really 
>>>> doesn't solve the
>>>> problems we have with const.
>>>
>>> 'mutable' doesn't really solve a problem, it just means that 
>>> C++ 'const' is a
>>> documentation aid, not a guarantee.
>>
>> It's still a guarantee for those members that aren't mutable. 
>> It's allowing
>> casting away const and mutating that totally blows the 
>> guarantees out of the
>> water.
>
> That's why such casts are not allowed in D @safe code.
>
> C++ const does not come with mechanically checkable guarantees, 
> and D's does. This makes all the difference.

Except that if you're calling 3rd party code, it's free to cast 
away const and mutate and slap an @trusted on there, and if it's 
more than one level deep in the call stack, they could slap an 
@safe on the function you're actually calling, and you wouldn't 
have a clue that they're violating the type system - and it could 
be with something you passed to them. Yes, @safe helps some, but 
ultimately, you still rely on the programmer who wrote the code 
you're using to behave responsibly. Ultimately, the D compiler 
doesn't prevent code from mutating const any more than the C++ 
compiler does. The primary differences are that C++ considers it 
defined behaved, whereas D does not, and D has immutable to worry 
about, whereas C++ does not. And unless the compiler is 
optimizing based on const, as long as the data in question was 
not constructed as immutable, casting away const and mutating 
will work in D just as well as it does in C++. So, it's easy for 
a programmer to think that it's perfectly legitimate to cast away 
const and mutate and then think that it's @system purely because 
of the possibility of the data actually being immutable and not 
even realize that it's undefined behavior even when the data was 
constructed as mutable. Even Andrei made that mistake fairly 
recently:

http://forum.dlang.org/post/n25qkc$2il8$1@digitalmars.com

He cast away const from the allocator member inside of a const 
member function so that he could provide access to it, since it 
was not part of the logical state of the container and really 
shouldn't have been const but had to be, because the container 
was const. @mutable is exactly what was needed in this case. But 
he (and Dicebot) thought that casting away const and mutating was 
defined behaved as long as the underlying data was mutable until 
I pointed out otherwise.

http://forum.dlang.org/post/resphkhblryhrlznxtbq@forum.dlang.org

While in theory, you can't cast away D's const and mutate, all 
that's preventing you is @safe, and it's clear that even expert D 
programmers who should arguably know better don't know better. 
I've heard (though haven't verified) that vibe.d casts away const 
to do reference counting, and it's clear from some of the 
stackoverflow answers that a number of D programmers think that 
casting away const and mutating is fine, because D is a systems 
language.

Programmers are casting away const and mutating in practice, and 
the compiler is not preventing it. We're in exactly the same boat 
as C++ in that we rely on the programmer to be smart about 
casting away const in order for const to provide any guarantees. 
We just made it undefined behavior when they do cast away const 
and made it warn about it slightly better by making it @system. 
But it still works in practice, and folks are still doing it. So, 
ultimately, I don't think that the idea that D's const guarantees 
that the object isn't mutated via that reference holds water much 
better than it does with C++'s const, even if in theory it 
should. In both cases, it relies on the programmer to do the 
right thing, and the compiler can't do much if you insist on 
doing the wrong thing, thinking that you know what you're doing. 
And the fact that it actually works in practice to cast away 
const and mutate doesn't help matters any in preventing it.

> Allow @mutable, and no more mechanical checking in D. Recall 
> that D supports opaque types, meaning types are not fully known 
> to the compiler.

Yes, which is why I said that a type with an @mutable member 
would be forced to be marked with @mutable as well (or something 
like @has_mutable if it's problematic to reuse the attribute on 
the class/struct). It would be the same as with an abstract 
class. So, then anything that wouldn't work with @mutable (e.g. 
constructing the type as immutable) could be statically 
prevented, even if the type were opaque, just like you can't 
construct an abstract class. it would obviously have to bubble up 
such that a type that contains an @mutable type would also have 
to be an @mutable type, but it would solve the opaque type 
problem.

- Jonathan M Davis


More information about the Digitalmars-d mailing list