static foreach and new identifier names

Adam D. Ruppe destructionator at gmail.com
Fri Jan 5 17:41:23 UTC 2018


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.


More information about the Digitalmars-d mailing list