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/resphkhblryhrlznx...@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

Reply via email to