On Wednesday, 25 December 2024 at 07:49:28 UTC, sfp wrote:
I have some code like this:

...

Thanks again for all the helpful feedback. This is where I landed:
```
import std.algorithm : map;
import std.algorithm.iteration : joiner;
import std.array : array;

string uncap(string s) {
  import std.format;
  import std.uni;
  return format("%s%s", s[0].toLower, s[1..$]);
}

enum string[] domains = [
  "Ball",
  "Box",
  "CsgDiff",
  "CsgIsect",
  "CsgUnion",
  "Rect",
];

auto getTypeString(string[] types) {
  return "enum Type {" ~ types.joiner(", ").array ~ "}";
}

auto getUnionString(string[] types) {
  return (
    ["union {"] ~
    types.map!(s => s ~ "!Dim " ~ uncap(s) ~ ";").array ~
    ["}"]
  ).joiner("\n").array;
}

string getCtorString(string s) {
  return
    "this(" ~ s ~ "!Dim " ~ uncap(s) ~ ") {\n" ~
    "  this.type = Type." ~ s ~ ";\n" ~
    "  this." ~ uncap(s) ~ " = " ~ uncap(s) ~ ";\n" ~
    "}\n";
}

auto getCtorStrings(string[] types) {
  return types.map!(getCtorString).array;
}

struct Domain(int Dim) {
  mixin(getTypeString(domains));
  Type type;
  mixin(getUnionString(domains));
  static foreach (ctorString; getCtorStrings(domains))
    mixin(ctorString);

  Rect!Dim getBoundingBox() const {
    final switch (type)
      static foreach (s; domains) case mixin("Type." ~ s):
        return mixin(uncap(s) ~ ".getBoundingBox()");
  }

  Domain!Dim intersect(const ref Domain!Dim other) const {
    final switch (type)
      static foreach (s1; domains) case mixin("Type." ~ s1):
        final switch (other.type)
          static foreach (s2; domains) case mixin("Type." ~ s2):
return mixin(uncap(s1) ~ ".intersect(other." ~ uncap(s2) ~ ")");
  }
}
```
This is enough to get me unstuck so I can write more actual code, but it still seems less than ideal:

1. It would be nice to be able to define the list of domains in terms of the actual types rather than strings. 2. As an added bonus, if I could validate that the types are all compatible with each other as templates (e.g., in this case they're all template classes with a single integer parameter), that would be useful. 3. It would be nice to come up with an abbreviated syntax for `getBoundingBox` and `intersect`, so that this starts looking a little more like a DSL for stubbing out interfaces.

Reply via email to