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

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

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

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)

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.

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

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.

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

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.

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.

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