On Wed, Jan 03, 2024 at 04:50:57PM +0000, axricard via Digitalmars-d-learn wrote: > I have an interface that is implemented by many classes, and I want to > pick one of these implementations at random. There are two more > constraints : first the distribution is not uniform, all classes can > define the chance they have to be picked (this is reflected by the > function 'weight()' below). And all classes are not always available, > this depends on some runtime information.
I would tag each implementation with a compile-time enum and use compile-time introspection with CRTP[1] to auto-generate the code for choosing a class according to the desired distribution. [1] https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern Something like this: ----------SNIP----------- import std.stdio; interface MyIntf { void work(); } struct ImplemInfo { int weight; MyIntf function() instantiate; } ImplemInfo[] implems; // list of implementations int totalWeight; MyIntf chooseImplem() { import std.random; auto pick = uniform(0, totalWeight); auto slice = implems[]; assert(slice.length > 0); while (slice[0].weight <= pick) { pick -= slice[0].weight; slice = slice[1 .. $]; } return slice[0].instantiate(); } // Base class that uses CRTP to auto-register implementations in // .implems without needing too much boilerplate in every // subclass. class Base(C) : MyIntf { // Derived class must define a .weight member readable // at compile-time. static assert(is(typeof(C.weight) : int), "Derived class must define .weight"); static this() { implems ~= ImplemInfo(C.weight, () { return cast(MyIntf) new C; }); totalWeight += C.weight; } // Derived classes must implement this abstract void work(); } // These classes can be anywhere class Implem1 : Base!Implem1 { enum weight = 1; override void work() { writeln(typeof(this).stringof); } } class Implem2 : Base!Implem2 { enum weight = 2; override void work() { writeln(typeof(this).stringof); } } class Implem3 : Base!Implem3 { enum weight = 3; override void work() { writeln(typeof(this).stringof); } } void main() { // pipe output of program to `sort | uniq -c` to verify that the // required distribution is generated correctly. foreach (_; 0 .. 100) { auto impl = chooseImplem(); impl.work(); } } ----------SNIP----------- --T