Shared global initialization

WB witold.baryluk at gmail.com
Sat Aug 2 21:18:26 UTC 2025


I like global registration patterns, for some stuff. Things like 
command line flags in very big projects with many tunable in 
various subsystems. Or registering things like benchmarks, etc. 
See for example Abseil flags, Go flags, or google benchmark tests.

But I think in D it is hard to pull off compared to for example 
C++. (Or some compiler tricks with linker sections).

Lets consider code like this:

```d
// Library code, i.e. flags.d

shared final class Flag {
   this(string name, string help = "") {
     import std.stdio : writefln;
     writefln("Constructing %s", name);

     name_ = name;
     help_ = help;
   }
   const string name_;
   const string help_;
   int val_;

   void print() {
     import std.stdio : writefln;
     writefln("%s=%d  # %s", name_, val_, help_);
   }

   shared static Flag[] flags;
}


string flag(string name, string help = "") {
   import std.conv : text;
   string s;
   s ~= i"shared Flag $(name);\n".text;
   // Alternatively we can do append to `Flag.flags` in `Flag` 
constructor.
   s ~= i"shared static this() { $(name) = new Flag(\"$(name)\", 
\"$(help)\"); Flag.flags ~= $(name); }\n".text;
   return s;
}


// User code, i.e. main.d
mixin(flag("foo", "--foo bar baz"));
mixin(flag("x", "--x y z"));

void main() {
   foo.print();
   x.print();
}
```



I really wish I was able to do something like this instead:


```d
shared final class Flag {
   this(string name, string help = "") {
     import std.stdio : writefln;
     writefln("Constructing %s", name);

     name_ = name;
     help_ = help;

     flags ~= this;
   }
   const string name_;
   const string help_;
   int val_;

   void print() {
     import std.stdio : writefln;
     writefln("%s=%d  # %s", name_, val_, help_);
   }

   shared static Flag[] flags;
}


shared Flag foo = new Flag("foo", "--foo bar baz");
shared Flag x = new Flag("foo", "--x y z");

void main() {
   foo.print();
   x.print();
}
```

But that does not work afaik.

And also for this to not be legal: `Flag foo = new Flag("foo", 
"--foo bar baz");`  (non-shared instantiation as global not 
allowed, maybe only in unittests allowed).

Am I missing something?

(Another pattern is to make `Flag` a immutable struct, and 
annotate it with UDF, then have at the end some mixin that 
iterates over all flags and initializes / registers them, but 
that is not pretty either).

```d
@flag("foo")
immutable Flag foo = FlagSpec("--foo bar baz");

mixin(iter_flags_and_register());
```

or something similar.



There must be some better, easier and less error prone way of 
doing this.

Cheers.



More information about the Digitalmars-d mailing list