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