On 06/18/12 14:45, deadalnix wrote: > Le 18/06/2012 07:59, Matthias Walter a écrit : >> On 06/18/2012 07:36 AM, Mehrdad wrote: >>> Is it just me, or did I subvert the type system here? >>> >>> >>> import std.stdio; >>> >>> struct Const >>> { >>> this(void delegate() increment) >>> { this.increment = increment; } >>> int a; >>> void delegate() increment; >>> void oops() const { this.increment(); } >>> } >>> >>> void main() >>> { >>> Const c; >>> c = Const({ c.a++; }); >>> writeln(c.a); >>> c.oops(); >>> writeln(c.a); >>> } >>> >> >> I don't think so. When calling oops you have two references to the object c: >> >> - The this-pointer of the object itself which is not allowed to change >> the object in the const-call. >> - The reference from within main which is allowed to change it and can >> be reached via the frame pointer of the delegate. >> >> I see this as perfectly valid code. Of course, opinions may differ here. >> >> Matthias > > The hidden parameter of the delegate is stored in c. This hidden parameter > must be qualified with const when c is made const, for transitivity. However, > it isn't. > > In short : > - c is made const > - the frame pointer is stored in c > - the frame pointer must be made const for transitivity. > > => The type system is broken. You'll find many examples of this behavior with > delegates.
It's fine, if you view a delegate as opaque. 'this' being const does not preclude accessing the object that 'this' points to via another, mutable, reference. Consider the alternative - you'd have to forbid storing any delegate with a non-const non-value argument inside any object. And "breaking" const would then _still_ be possible and trivial. import std.stdio; S*[const(S)*] g; struct S { int i; this(int i) { this.i = i; g[&this] = &this; } void f() const { g[&this].i=666; } } void main() { const s = S(42); writeln(s); s.f(); writeln(s); } Yes, D's "pure" could help here, only it's misnamed (even if in this particular case that term would be fitting). artur