Run-time initialised static variables

dekevin dekevin at student.ethz.ch
Wed Feb 7 12:10:38 UTC 2018


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));
      }
}


More information about the Digitalmars-d-learn mailing list