On 2011-09-29 14:54:24 +0000, "Steven Schveighoffer" <[email protected]> said:

I just thought of an interesting way to make a logical const object without casts. It requires a little extra storage, but works without changes to the current compiler (and requires no casts).

Here's the code, then I'll talk about the implications:

import std.stdio;

class D
{
     D getme() { return this;}
     void foo() {writeln("mutable!");}
}

class C
{
     D delegate() d;
     this()
     {
       auto dinst = new D;
       this.d = &dinst.getme;
     }
     void bar() const { d().foo();}
}

void main()
{
     auto c = new C;
     c.bar();
}

outputs:

mutable!

So how does it work? It works because delegates and especially the delegate data is *not* affected by const. So even when C is temporarily cast to const, the delegate is not affected (i.e. it's context pointer is not temporarily cast to const).

Doesn't this poke holes in const? Of course it does, but no more holes than are present via another logical const scheme (i.e. using a globally stored AA to retrieve the data).

This is a hole in the transitive const, because the delegate contains a pointer to mutable data. It also is a potential source of of low level races since returning that type from a pure function could make it immutable, which can then make this mutable data accessible to multiple threads with no synchronization or atomics to protect the data's integrity.


I'm actually thinking that very controlled patterns of logical const like this could be implemented via mixin, and be sanctioned by the library. The way this pattern works, you can dictate as the author of a class whether that class can be a logically const part of another object or not, simply by choosing to implement getme or not.

Whatever the implementation I think this is deeply needed. It is needed because people are trying all sorts of things to work around const transitivity, many of which are subtly unsafe.


--
Michel Fortin
[email protected]
http://michelf.com/

Reply via email to