Thread overview
Ctor, setters and invariant
Mar 02, 2013
simendsjo
Mar 02, 2013
Maxim Fomin
Mar 02, 2013
Simen Kjærås
March 02, 2013
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?
March 02, 2013
Make a property private?

March 02, 2013
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