How to break const

Christophe Travert travert at phare.normalesup.org
Tue Jun 19 10:30:21 PDT 2012


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
   }
   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
      f(t);
   }

   void f(const (T)* t) {
      t.f(t.i*2); // legal because T.f is const
   }

-- 
Christophe


More information about the Digitalmars-d mailing list