Re: Run-time initialised static variables

2018-02-09 Thread dekevin via Digitalmars-d-learn

On Tuesday, 6 February 2018 at 23:03:07 UTC, dekevin wrote:

Hello everyone,
I just ran into the problem, that I need a static variable, 
where the initialisation code for that variable is only 
accessible during run-time (since part of the initialisation 
code will be dynamically linked).


Is there a way to do this in D?

To be a bit more concrete, this is where I have the problem 
(where ℚ uses GMP, which is dynamically linked):


struct ℚInf {
   ℚ qval;
   immutable static ℚInf zero = ℚInf(0,1);
   this(long num, long den) {
qval = ℚ(num,den); //this initialisation requires 
dynamically linked code

}
}


In case anyone is curios, thanks to tgehr i was able to resolve 
the issue.

For static variables:
struct ℚInf {
ℚ qval;
static ℚInf zero = void;
static this() {
zero = ℚInf(0,1);
}
 }

For immutable static variables (a bit hacky since it sidesteps 
the type system):

struct ℚInf {
ℚ qval;
immutable static ℚInf zero = void;
static this() @trusted {
import std.conv: emplace;
emplace!ℚInf(cast(ℚInf*),ℚInf(0,1));
}
 }



Re: Run-time initialised static variables

2018-02-07 Thread dekevin via Digitalmars-d-learn

On Wednesday, 7 February 2018 at 20:10:10 UTC, dekevin wrote:
On Wednesday, 7 February 2018 at 16:26:16 UTC, Dominikus Dittes 
Scherkl wrote:

On Wednesday, 7 February 2018 at 12:10:38 UTC, dekevin wrote:



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


You can use a different default initializer:
  ℤ num = 0, den = 1;

Thus avoiding the bad denominator.


I appreciate the help, but I cannot instantiate these variables 
with a constructor.
Whenever I do, the compiler tries to figure out its values at 
compile-time.
This it cannot do however, since the code requires gmp_init for 
constructing an explicit value, which is only available after 
dynamically linking GMP.


Here is the error I get:
 source/gmp/z.d(117): Error: __gmpz_init_set_si cannot be 
interpreted at compile time, because it has no available source 
code
 source/util.d(575):called from here: 
_MpZ(__mpz_struct(0, 0, null)).this(0)
 source/gmp/z.d(117): Error: __gmpz_init_set_si cannot be 
interpreted at compile time, because it has no available source 
code
 source/util.d(575):called from here: 
_MpZ(__mpz_struct(0, 0, null)).this(1)


I don't really know what to do now, since I have another struct 
which already uses static variables with the same naming 
convention and I'll also need it a second time when I write the 
bindings to MPFR.


I should perhaps add how  ℤ looks like.
Here is a stripped-down version:

struct ℤ {
@disable this();
this(T)(T value) @trusted
if (isArithmetic!T)
{
version(ccc) { ++_ccc; }
static  if (isUnsigned!T)
__gmpz_init_set_ui(_ptr, value);
else static if (isFloating!T)
__gmpz_init_set_d(_ptr, value);
else// isSigned integral
__gmpz_init_set_si(_ptr, value);
}

~this() @trusted
{
assert(_ptr, "Pointer is null");
//if(hasBeenInit)
__gmpz_clear(_ptr); version(ccc) { ++_ccc; }

}

inout(__mpz_struct)* _ptr() inout return @system
{
return &_z;
}
}


Re: Run-time initialised static variables

2018-02-07 Thread dekevin via Digitalmars-d-learn
On Wednesday, 7 February 2018 at 16:26:16 UTC, Dominikus Dittes 
Scherkl wrote:

On Wednesday, 7 February 2018 at 12:10:38 UTC, dekevin wrote:



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


You can use a different default initializer:
  ℤ num = 0, den = 1;

Thus avoiding the bad denominator.


I appreciate the help, but I cannot instantiate these variables 
with a constructor.
Whenever I do, the compiler tries to figure out its values at 
compile-time.
This it cannot do however, since the code requires gmp_init for 
constructing an explicit value, which is only available after 
dynamically linking GMP.


Here is the error I get:
 source/gmp/z.d(117): Error: __gmpz_init_set_si cannot be 
interpreted at compile time, because it has no available source 
code
 source/util.d(575):called from here: 
_MpZ(__mpz_struct(0, 0, null)).this(0)
 source/gmp/z.d(117): Error: __gmpz_init_set_si cannot be 
interpreted at compile time, because it has no available source 
code
 source/util.d(575):called from here: 
_MpZ(__mpz_struct(0, 0, null)).this(1)


I don't really know what to do now, since I have another struct 
which already uses static variables with the same naming 
convention and I'll also need it a second time when I write the 
bindings to MPFR.


Re: Run-time initialised static variables

2018-02-07 Thread dekevin via Digitalmars-d-learn
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));
 }
}


Re: Run-time initialised static variables

2018-02-06 Thread dekevin via Digitalmars-d-learn

On Tuesday, 6 February 2018 at 23:50:52 UTC, dekevin wrote:
On Tuesday, 6 February 2018 at 23:21:36 UTC, Jonathan M Davis 
wrote:

[...]


Thanks a lot! I will change all my initialisations to static 
constructors now.
The only additional problem I have, is that ℚInf has a disabled 
default constructor.
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
  }
}

Best,
Kevin


I should perhaps add, that I get the following DMD error message:
source/intervalarithmeticrationals.d(15): Error: variable 
intervalarithmeticrationals.ℚInf.posinf default construction is 
disabled for type immutable(ℚInf)


Re: Run-time initialised static variables

2018-02-06 Thread dekevin via Digitalmars-d-learn
On Tuesday, 6 February 2018 at 23:21:36 UTC, Jonathan M Davis 
wrote:
On Tuesday, February 06, 2018 23:03:07 dekevin via 
Digitalmars-d-learn wrote:

Hello everyone,
I just ran into the problem, that I need a static variable, 
where

the initialisation code for that variable is only accessible
during run-time (since part of the initialisation code will be
dynamically linked).

Is there a way to do this in D?

To be a bit more concrete, this is where I have the problem 
(where ℚ uses GMP, which is dynamically linked):


struct ℚInf {
ℚ qval;
immutable static ℚInf zero = ℚInf(0,1);
this(long num, long den) {
 qval = ℚ(num,den); //this initialisation requires
dynamically linked code
 }
}


So, you want qval to be static and initialized at runtime? Then 
use a static constructor. e.g.


struct QInf
{
...
static this()
{
qval = ...;
}
...
}

That doesn't work if you're dealing with a static local 
variable, but it works for static members of structs and 
classes, and it works for module-level variables.


And if you want to make qval immutable, then use a shared 
static constructor. e.g.


struct QInf
{
...
shared static this()
{
qval = ...;
}
...
}

You can currently initialize immutable static variables with 
non-shared static constructors, but that's a bug and will 
result in the immutable variable being reinitialized whenever a 
new thread is created.


- Jonathan M Davis


Thanks a lot! I will change all my initialisations to static 
constructors now.
The only additional problem I have, is that ℚInf has a disabled 
default constructor.
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
  }
}

Best,
Kevin


Run-time initialised static variables

2018-02-06 Thread dekevin via Digitalmars-d-learn

Hello everyone,
I just ran into the problem, that I need a static variable, where 
the initialisation code for that variable is only accessible 
during run-time (since part of the initialisation code will be 
dynamically linked).


Is there a way to do this in D?

To be a bit more concrete, this is where I have the problem 
(where ℚ uses GMP, which is dynamically linked):


struct ℚInf {
   ℚ qval;
   immutable static ℚInf zero = ℚInf(0,1);
   this(long num, long den) {
qval = ℚ(num,den); //this initialisation requires 
dynamically linked code

}
}