December 25

On Wednesday, 25 December 2024 at 21:23:00 UTC, Jim Balter wrote:

>

I suggest reading the spec rather
than just trying random things.

I suggest trying random things instead of reading the spec. The spec is full of lies and slander, and when your in template hell, defensively syntax test to find the compiler bugs before you glue all your code together.

December 25

On Wednesday, 25 December 2024 at 21:34:00 UTC, monkyyy wrote:

>

On Wednesday, 25 December 2024 at 21:23:00 UTC, Jim Balter wrote:

>

I suggest reading the spec rather
than just trying random things.

I suggest trying random things instead of reading the spec. The spec is full of lies and slander, and when your in template hell, defensively syntax test to find the compiler bugs before you glue all your code together.

Defensive testing isn't inconsistent with learning and understanding the language rather than just randomly guessing what might work.

December 25

On Wednesday, 25 December 2024 at 18:25:57 UTC, sfp wrote:

>

kind of weird that it doesn't work inside enum.
Seems like an obvious application...

It's not weird at all when you understand that it's an AST that is being mixed in, not just a string as if it were an C preprocessor macro. The insides of enum { ... } is not an expression so it makes no sense to try to mix in an expression. enums are
indeed an obvious application for mixins, but that's just not the way you do it. Here's are some mixins I wrote just yesterday:

string membersListMixin(alias T)() {
  string s;
  foreach (member; __traits(allMembers, T)) {
    s ~= member ~ ", ";
  }
  return s;
}

enum NamedEnum { // named so I can generate its fields
  field1 = "string1",
  field2 = "string2",
  // ...
}


void foo() {
  foreach (field; mixin(`[`, membersListMixin!NamedEnum, `]`)) {
    // do something with field
  }
}


string anonymousEnumMixin(alias E)() {
  string s = "enum { ";
  foreach (member; __traits(allMembers, E)) {
    s ~= member ~ " = " ~ E.stringof ~ "." ~ member ~ ", ";
  }
  return s ~ "}";
}

mixin(anonymousEnumMixin!NamedEnum);
// now I can refer to field1, field2, etc. without qualifying them.
December 25

On Wednesday, 25 December 2024 at 21:23:00 UTC, Jim Balter wrote:

>

On Wednesday, 25 December 2024 at 16:41:05 UTC, sfp wrote:

>

On Wednesday, 25 December 2024 at 07:57:04 UTC, monkyyy wrote:

>

static foreach, traits and mixin

I was looking into this but I think I need some help getting off the ground...

This doesn't compile:

enum Test { mixin("A, B, C") }

No, but mixin("enum Test {", "A, B, C", "}"); does. There are mixin statements, which that is, and there are mixin expressions, which you tried, but you can't put an expression there and A, B, C isn't one. I suggest reading the spec rather than just trying random things.

Language specs aren't a good resource for learning. I'm also not trying random things. I have a clear idea of what I want to do, and I'm in the process of learning how D does its thing, and whether its a reasonable choice for me. I've found an example which is simplified and closely related to something I want to do. It fails and the compiler errors aren't helpful. I've posted it here and gotten detailed responses from people who know what's going on. Extremely useful. Thanks in advance for your patience, since I will invariably be posting more of the same.

December 26

On Wednesday, 25 December 2024 at 07:49:28 UTC, sfp wrote:

>

I have some code like this:

enum DomainType {
  Ball,
  Box,
  CsgDiff
}

struct Domain(int Dim) {
  DomainType type;
  union {
    Ball!Dim ball;
    Box!Dim box;
    CsgDiff!Dim csgDiff;
  }

  this(Ball!Dim ball) {
    this.type = DomainType.Ball;
    this.ball = ball;
  }

  this(Box!Dim box) {
    this.type = DomainType.Box;
    this.box = box;
  }

  this(CsgDiff!Dim csgDiff) {
    this.type = DomainType.CsgDiff;
    this.csgDiff = csgDiff;
  }

  void doSomething() {
    switch (type) {
    case DomainType.Ball:
      ...
      break;
    case DomainType.Box:
      ...
      break;
    case DomainType.CsgDiff:
      ...
      break;
    }
  }
}

Is there some way I can reduce the amount of boilerplate using D, i.e. generate most of this code at compile time?

For what it's worth, I had checked out SumType as an alternative to this mess, but it doesn't play nicely with recursively defined types.

Here's how I would improve upon your code with mixin and static foreach.

enum DomainType {
  Ball,
  Box,
  CsgDiff
}

const DomainTypeShortNames =
    [
    	DomainType.Ball : "ball",
    	DomainType.Box : "box",
    	DomainType.CsgDiff : "csgDiff"
    ];

struct Domain(int Dim) {
  DomainType type;
  union {
    static foreach (domainType; EnumMembers!DomainType)
    {
        mixin(domainType.to!string ~ "!Dim " ~ DomainTypeShortNames[domainType] ~ ";");
    }
  }

  static foreach (domainType; EnumMembers!DomainType)
  {
      mixin(q{
          this(%1$s!Dim %2$s)
          {
              this.type = DomainType.%1$s;
              this.%2$s = %2$s;
          }
      }.format(domainType, DomainTypeShortNames[domainType]));
  }

  ...
}
December 26

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.
December 27

On Wednesday, 25 December 2024 at 21:34:00 UTC, monkyyy wrote:

>

The spec is full of lies and slander,

>

noun: lie; plural noun: lies
an intentionally false statement.

Can you please stop saying that the spec is intentionally false?

December 28

On Friday, 27 December 2024 at 11:31:05 UTC, Nick Treleaven wrote:

>

On Wednesday, 25 December 2024 at 21:34:00 UTC, monkyyy wrote:

>

The spec is full of lies and slander,

>

noun: lie; plural noun: lies
an intentionally false statement.

Can you please stop saying that the spec is intentionally false?

The spec would need to drastically improve before my opinion changes; Im also uninterested practicing withholding my opinions.

There are many many ancient bugs, that you need to inherent implicit knowledge to navigate, either those a) should actually be fixed or b) the spec should make such knowledge explicit

December 29

On Saturday, 28 December 2024 at 23:23:02 UTC, monkyyy wrote:

>

The spec would need to drastically improve before my opinion changes; Im also uninterested practicing withholding my opinions.

There are many many ancient bugs, that you need to inherent implicit knowledge to navigate, either those a) should actually be fixed or b) the spec should make such knowledge explicit

On the other hand, I'd characterize the language as very nicely designed, and the spec and Programming in D to be tremendously helpful. The responsiveness and quality of comments on this forum has always sufficed to fill in the gaps. Just recently a submitted a bug on Phobos, which was quickly and kindly narrowed down to something else (changed ldc2 default).

The community is the real treasure.

Can the spec be improved? No doubt. I hope you can find a way to get the flaws you've found incorporated.

Andy

December 29

On Sunday, 29 December 2024 at 15:15:28 UTC, Andy Valencia wrote:

>

On Saturday, 28 December 2024 at 23:23:02 UTC, monkyyy wrote:

>

The spec would need to drastically improve before my opinion changes; Im also uninterested practicing withholding my opinions.

There are many many ancient bugs, that you need to inherent implicit knowledge to navigate, either those a) should actually be fixed or b) the spec should make such knowledge explicit

On the other hand, I'd characterize the language as very nicely designed,

Where that is true, I doubt the spec was involved. The spec bullet points look like compiler peusdo code or formalizing wontfix bugs while burying the lead.

>

Just recently a submitted a bug on Phobos, which was quickly and kindly narrowed down to something else (changed ldc2 default).
I hope you can find a way to get the flaws you've found incorporated.

At this point if I found a bug I needed fixed id complain to adr, and even then I assume ill find a bug with templates once a week after leaving the garden path.