www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Ctor, setters and invariant

reply "simendsjo" <simendsjo gmail.com> writes:
invariant is called when a method enters. This creates problems 
if the constructor calls a setter:

import std.exception;
struct S {
   private int _i;
   public:
   this(int i) {
     this.i = i;
   }
    property void i(int v) {
     enforce(v > 1);
     _i = v;
   }
   invariant() {
     assert(_i > 1);
   }
}
unittest {
   S(10);
}
void main() {}


In this example, invariant is called at the start if the property 
i called through the constructor. Calling setters in constructors 
is sometimes a good way to make sure everything is initialized 
properly, but as invariant is called, this becomes impossible.

Is it possible that invariant() is only called at the end of ctor 
instead of at the beginning and end of each setter when called 
from the ctor? The ctor will often have the object in an invalid 
state while constructing the object, so calling invariant() while 
in ctor will almost always create problems.

Or does anyone know a better way to solve this that doesn't 
require code duplication?
Mar 02 2013
next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
Make a property private?
Mar 02 2013
prev sibling parent =?iso-8859-15?Q?Simen_Kj=E6r=E5s?= <simen.kjaras gmail.com> writes:
On Sat, 02 Mar 2013 11:02:08 +0100, simendsjo <simendsjo gmail.com> wrote:

 invariant is called when a method enters. This creates problems if the  
 constructor calls a setter:

 import std.exception;
 struct S {
    private int _i;
    public:
    this(int i) {
      this.i = i;
    }
     property void i(int v) {
      enforce(v > 1);
      _i = v;
    }
    invariant() {
      assert(_i > 1);
    }
 }
 unittest {
    S(10);
 }
 void main() {}


 In this example, invariant is called at the start if the property i  
 called through the constructor. Calling setters in constructors is  
 sometimes a good way to make sure everything is initialized properly,  
 but as invariant is called, this becomes impossible.

 Is it possible that invariant() is only called at the end of ctor  
 instead of at the beginning and end of each setter when called from the  
 ctor? The ctor will often have the object in an invalid state while  
 constructing the object, so calling invariant() while in ctor will  
 almost always create problems.

 Or does anyone know a better way to solve this that doesn't require code  
 duplication?
import std.exception; struct S { private int _i; private bool inConstructor = true; public: this(int i) { this.i = i; this.inConstructor = false; } property void i(int v) { enforce(v > 1); _i = v; } invariant() { if (inConstructor) return; assert(_i > 1); } } unittest { S(10); } void main() {} Not perfect, but it works. -- Simen
Mar 02 2013