www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Logical Const using a Mutable template

reply Jesse Phillips <jessekphillips+D gmail.com> writes:
This came up in discussion and I think the behavior is safe and usable when
wanting to change class data in a const function.

http://article.gmane.org/gmane.comp.lang.d.general/43476

One limitation is that value types declared as Mutable (Mutable!(int)) can not
be changed if the encapsulating class is declared immutable. For this reason a
Mutable value can not be changed inside a const function. I think this is
acceptable.

Another limitation appears to be an issue with alias this. It is commented as a
//FIXME in the code.

https://gist.github.com/721066

An example usage looks like:

    class Inner { int n; }

    class A {
        Mutable!(int*) n;
        Mutable!(int)  n2;
        Mutable!(Inner) innerClass;
        this() { n = new int; innerClass = new Inner; }

        void foo( int num ) {
            n2 = num;
        }
        
        void bar( int num ) const {
            innerClass.n = num;
        }
    }

    auto aImmu = new immutable(A);
    auto aMu   = new A;
    int i = 8;
    
    *aImmu.n = i,
    aImmu.bar(6),
    *aMu.n = i,
    aMu.n = &i,
    aMu.n2 = i,
    aMu.bar(6),
    aMu.foo(6),
Nov 29 2010
parent reply Max Samukha <spambox d-coding.com> writes:
On 11/30/2010 09:30 AM, Jesse Phillips wrote:
 This came up in discussion and I think the behavior is safe and usable when
wanting to change class data in a const function.

 http://article.gmane.org/gmane.comp.lang.d.general/43476

 One limitation is that value types declared as Mutable (Mutable!(int)) can not
be changed if the encapsulating class is declared immutable. For this reason a
Mutable value can not be changed inside a const function. I think this is
acceptable.

 Another limitation appears to be an issue with alias this. It is commented as
a //FIXME in the code.

 https://gist.github.com/721066

 An example usage looks like:

      class Inner { int n; }

      class A {
          Mutable!(int*) n;
          Mutable!(int)  n2;
          Mutable!(Inner) innerClass;
          this() { n = new int; innerClass = new Inner; }

          void foo( int num ) {
              n2 = num;
          }

          void bar( int num ) const {
              innerClass.n = num;
          }
      }

      auto aImmu = new immutable(A);
      auto aMu   = new A;
      int i = 8;

      *aImmu.n = i,
      aImmu.bar(6),
      *aMu.n = i,
      aMu.n =&i,
      aMu.n2 = i,
      aMu.bar(6),
      aMu.foo(6),

It is not enough to forward opAssign and opEquals. Any operator should be handled. For example, change the implementation of A.foo to n2 += 1; and you will get a segfault during compilation. You could add more kludge with operator overloads but I don't think it is worth the effort. It makes more sense to wait until "alias this" bugs are fixed. On the other hand, we may wait forever since the way "alias this" should handle operators has never been specified.
Nov 30 2010
parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
Max Samukha Wrote:

 On 11/30/2010 09:30 AM, Jesse Phillips wrote:
 This came up in discussion and I think the behavior is safe and usable when
wanting to change class data in a const function.

 http://article.gmane.org/gmane.comp.lang.d.general/43476

 One limitation is that value types declared as Mutable (Mutable!(int)) can not
be changed if the encapsulating class is declared immutable. For this reason a
Mutable value can not be changed inside a const function. I think this is
acceptable.

 Another limitation appears to be an issue with alias this. It is commented as
a //FIXME in the code.

 https://gist.github.com/721066

It is not enough to forward opAssign and opEquals. Any operator should be handled. For example, change the implementation of A.foo to n2 += 1; and you will get a segfault during compilation. You could add more kludge with operator overloads but I don't think it is worth the effort. It makes more sense to wait until "alias this" bugs are fixed. On the other hand, we may wait forever since the way "alias this" should handle operators has never been specified.

The intent isn't to work around alias this bugs. It is to provide mutation in a const function, but with the guarantee that it will not result in undefined behavior. (I should have stated that first, but it was getting late). Concurrency shouldn't be any different from having a reference in a class you are sharing. Sharing immutable objects should be fine as they still can not have their state changed. The rules for this are: * Only mutable data can be assigned to a Mutable * Modification of referenced fields can be modified (inner class fields, pointer targets) I'll be back to finish this in a bit.
Nov 30 2010
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Jesse Phillips Wrote:

 The rules for this are:
 
 * Only mutable data can be assigned to a Mutable
 * Modification of referenced fields can be modified (inner class fields,
pointer targets)
 
 I'll be back to finish this in a bit.

* Value types can be modified if the encapsulating class is not declared const/immutable And I have come up with 2 major concerns related to immutable classes. Would an inner class be placed in read-only memory in instantiating an immutable class: class A { Mutable!(Inner) innerclass; this() { innerclass = new Inner; } // Is innerclass placed in read-only memory } new immutable(A); And what about when an immutable instance is passed to a thread or network. Would the innerclass be placed in read-only memory for the new thread/machine. And looking over it again, I found that I wasn't using the opAssign const functions, they didn't meet the requirements. So I think a working alias this would allow the template to be: (The important check being that Mutables are unqualified) struct Mutable( T ) if ( is( T : Unqual!T ) ) { private T _payload; this( T t ) { _payload = t; } trusted property ref T get( )( ) const { T* p = cast( T* )&_payload; return *p; } alias get this; } https://gist.github.com/721066
Nov 30 2010