Y'all know if we write this:

static foreach(foo; [1,2,3]) {
        int blargh = foo;
}

we get:

e2.d(2): Error: variable e2.__anonymous.blargh conflicts with variable e2.__anonymous.blargh at e2.d(2) e2.d(2): Error: variable e2.__anonymous.blargh conflicts with variable e2.__anonymous.blargh at e2.d(2)


because it expands to

int blargh = 1;
int blargh = 2;
int blargh = 3;

all in the same scope. This makes static foreach of fairly little value to me - most times I have considered using it, I end up just using plain old string mixin instead so i can generate names for the declarations.


Well, how's this for a solution? Any time the compiler is expecting an identifier in a declaration, it can see the `mixin` keyword instead and expand that. The mixin expression must yield a string after passing through ctfe.

import std.conv;
static foreach(foo; [1,2,3]) {
        // so freaking ugly. but would now be legal:
        int mixin("\"blargh\"" ~ to!string(foo)) = foo;
}

---

int mixin("foo"); // illegal, it returned a symbol foo that doesn't exist

---

enum foo = "bar";
int mixin("foo"); // now legal, would define `int bar;`

---

int mixin(`"foo"`); // legal, same as `int foo;`




I find this to be pretty freaking hideous... but it is also the best idea I've had so far to rescue static foreach's value in making new declarations. It limits the string mixin part to just the name, I *think* the parser can handle it easily enough, and it gives all the ctfe flexibility we could use (including outside static foreach btw).

What do you all think?




ALTERNATIVE IDEA:

Make a special identifier known the compiler, let's call it `__unique_name` which is unique for any static foreach iteration.

static foreach(foo; [1, 2, 3]) {
   int __unique_name = foo;
}

now compiles, since each iteration gives a new magic unique name. But how do you refer to that in the outside world? With alias:

static foreach(foo; [1, 2, 3]) {
  int __unique_name = foo;
  mixin("alias " ~ ctfe_generated_name ~ " = __unique_name");
}


In a little example like this, that looks silly, you might as well just mixin the whole declaration, but for something like a large function, the mixin remains just that one same alias thing, while the rest of it is written normally. The alias will then be responsible for things like merging overloads, if necessary.

Reply via email to