On Wednesday, 7 February 2018 at 00:31:01 UTC, Jonathan M Davis wrote:
On Tuesday, February 06, 2018 23:50:52 dekevin via Digitalmars-d-learn wrote:
Thanks a lot! I will change all my initialisations to static constructors now.

I should point out that the downside to static constructors is that if you have modules that recursively depend on each other, the program throws an Error at startup, because the runtime can't determine the correct order of initialization. So, while static constructors can be very useful, you do have to be careful with them.

The only additional problem I have, is that ℚInf has a disabled default constructor.

D does not have default constructors. What you're really disabling is default initialization. This is an important distinction in understanding how objects are initialized in D. The init value is known at compile time and can't involve runtime stuff, whereas a default constructor would be able to run arbitrary code at runtime.

Is there a way to allow shared static constructors, but not the
default constructor?
struct ℚInf {
      ℚ qval;
      immutable static ℚInf zero;
     @disable this();
      shared static this() {
           zero.qval = ℚ(0);
      }
      this(long num, long den) {
           qval = ℚ(num,den); //this initialisation requires
  dynamically linked code
       }
}

If you're initializing an immutable variable, you have to initialize it in one go. What you're doing is letting it be default initialized (which results in a compilation error, because default initialiaztion is disabled for that type) and then assigning to one of its members. If the default initialization weren't disabled, you'd get an error about not being able to mutate an immutable variable, whereas the fact that you disabled default initialization but did not explicitly initialize the variable results in a compilation error about not initializing the variable.

If you want zero to be immutable, you must initialize the entire object at once. e.g.

zero = QInf(0, 0);

or whatever makes sense. If you need zero to be initialized differently from other QInfs, then you could make a private constructor that just takes the value for qval. But it either has to be default initialized with whatever the init type is (which you clearly don't want, since you disabled that), or it needs to be explicitly given a value.

- Jonathan M Davis

Ah I see the distinction between initialisation and construction now. Disabling default initialisation was necessary, because part of the code of the initialisation code of ℚ is linked at runtime (mainly to initialise ℤ, which relies on gmp_init which is linked at runtime).

But even if I initialise it in one go, the compiler still complains and wants to initialise posinf (complains that default construction is disabled). I also tested it with a static constructor and a non-immutable type and that didn't work either.

Here is a stripped down version of the important bits:

struct ℚInf {
    ℚ qval;
    enum Inf {
            negInf=-1,
            nonInf=0,
            posInf=+1,
    }
    Inf inf;
immutable static ℚInf posinf; //at this line the compiler complains that default construction is disabled for type immutable(ℚInf)

    @disable this();
    shared static this() {
        posinf = ℚInf(Inf.posInf);
        //neginf = ℚInf(Inf.negInf);
    }

    private this(Inf inf) {
        assert(inf != nonInf);
        this.inf = inf;
        qval = ℚ(0,1);
    }

    this(long num, long den) {
        inf=Inf.nonInf;
        qval = ℚ(num,den);
    }
}

struct ℚ{
ℤ num, den; //cannot call constructors on these, since they require gmp_init, which requires runtime code
     //Default initialiser disabled, since else num=0,den=0
     @disable this();
     this(long num){
          this(num.ℤ);
     }
     this(ℤ num){
          this.num=ℤ(num);
          this.den = 1;
     }
     this(ℤ num,ℤ den){
          assert(den != ℤ(0)); //Disable this for speed
          if(den<0){ num=-num; den=-den; }
          auto d=gcd(abs(num),den);
          num/=d, den/=d;
          this.num=num;
          this.den=den;
     }
     this(long num, long den) {
          this(ℤ(num),ℤ(den));
     }
}

Reply via email to