Le 19/06/2012 20:11, Artur Skawina a écrit :
On 06/19/12 19:30, Christophe Travert wrote:
Artur Skawina , dans le message (digitalmars.D:170175), a écrit :
On 06/19/12 15:29, deadalnix wrote:
Le 19/06/2012 14:30, Artur Skawina a écrit :
Due to D concept of weak purity, this doesn't ensure the required what we need
here.
Actually, it does - if it can be proved that the delegate can't alter the object
via the context pointer (eg because whatever it points to is not mutable) then
even D's "pure" is enough. Because the delegate would need to be passed a
mutable
ref to be able to alter the object, which then could hardly be constructed as
"breaking" constness.
But such a limit (const/immutable context) would be a problem for the cases
where
the delegate needs to alter some state (like export the result of some
operation),
but does _not_ modify the object it's embedded in. Note that the current object
may
very well be reachable (and mutable) from the delegate - but at some point you
have
to trust the programmer. Sure, fixing this hole would be great, but /how/ - w/o
incurring unacceptable collateral damage?
This isn't a problem as long as the delegate isn't a member of the object. If
it is, transitivity is broken, which is something you don't want.
Relying on the trust on the programmer is a dumb idea. Human do mistake, way
more than computers. The basic behavior MUST be a safe one.
Transitivity has been introduced for good reason and language already provide a
way to break it via cast. So it is unacceptable to rely on programmer on that
point.
It is possible to get the error when trying to call the delegate instead of
preventing to make it const, as I said in the post you quote. It is probably a
better solution.
Any delegate?
No, any delegate that have type that isn't covariant with the expected delegate
type.
struct S {
int i; this(int i) { this.i = i; }
T* p;
void f(int i) { this.i = i; /*p.i++;*/ }
}
struct T {
int i; this(int i) { this.i = i; }
void delegate(int i) f;
}
void main() {
auto t = new T(42);
auto s = new S(17);
s.p = t;
t.f =&s.f;
f(t);
}
void f(const (T)* t) {
t.f(t.i*2);
}
You're proposing to make the last 'f' function illegal, just because the
commented out part could happen. I'm saying that this is unlikely to happen
*by accident*, and of course would still be possible by casting away the
constness.
But banning "unsafe" delegates would result in casts *when using "safe" ones*
- which is not a real improvement because this would make the "bad" casts much
harder to spot.
The proper way to do this is not cast, it is to give the proper
constness for all types and methods :
struct S {
int i; this(int i) { this.i = i; }
T* p;
void f(int i) const { this.i = i; /*p.i++;*/ }
// the commented part is illegal because S.f is const
Not just the commented part.
}
struct T {
int i; this(int i) { this.i = i; }
void delegate(int i) const f;
// T.f is const to be callable from .f
}
void main() {
auto t = new T(42);
auto s = new S(17);
s.p = t;
t.f =&s.f; // legal when T.f is const because S.f is also const
Only a const T.f would be pointless.
Like I've already said twice in this thread - it *can* be done (the
function has to be "pure" too for it to work), but certain delegate
uses, which are OK now, would be forbidden.
Once again, this is inconsistent with how purity is defined elsewhere.
I'm all for fixing this hole - it's just that the proposed "fix" would
have consequences, which can't simply be ignored.
They are not ignored, but it seems you don't clearly understand the
implications and the big picture.