static foreach and new identifier names
H. S. Teoh
hsteoh at quickfur.ath.cx
Fri Jan 5 18:07:54 UTC 2018
On Fri, Jan 05, 2018 at 05:41:23PM +0000, Adam D. Ruppe via Digitalmars-d wrote:
> 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)
[...]
Simple solution: add another pair of {} to create a nested scope:
static foreach(foo; [1,2,3]) {{
int blargh = foo;
}}
Well, perhaps this looks just as hideous to your eyes, but at least we
didn't have to resort to mixins. :-D OTOH, if you actually need to
insert declarations into the containing scope that depends on these
temporary declarations, then this won't work.
I recently ran into a similar issue, not 100% sure whether it should be
considered a bug/enhancement request, but basically:
static foreach (x; blah) {{
struct S {
... // declarations that depend on x
}
S s;
... // do something with s
}}
Initially, I tried it without the double braces, but of course that
doesn't work because S is declared multiple times with incompatible
definitions. But even with the double braces, the compiler complained
"identifier S is already declared in another scope". :-( Apparently,
it's illegal to reuse the same identifier in the same function, even
though each declaration is actually in its own disjoint scope.
Two solutions occurred to me at the time: (1) create a new identifier
namespace with a nested function. I found this far too ugly, so I
ditched the idea. (2) Use a mixin to create new names for each
declaration, which is what you proposed. But that meant putting a lot of
code inside a string, which is extremely ugly (even if D does have token
strings, which alleviated the ugliness a little bit, but only a little
bit).
Then suddenly it struck me: (1) What we need is a way to create new
identifiers that depends on some compile-time entity, like the loop
variable of a static foreach. (2) A template instantiated with some
compile-time entity as argument creates a new, unique name for that
particular template instantiation. Put these two together, and Bingo!:
struct S(x) { // or alias x, depending on what x is
... // declarations that depend on x
}
static foreach (x; blah) {{
S!x s; // <--- this is the magic right here
... // do something with s
}}
Problem solved. :-D
In your case, you might be able to do something similar:
struct MyInt(int foo) {
int blargh = foo;
alias blargh this;
}
static foreach(foo; [1,2,3]) {{
MyInt!foo blargh;
}}
alias this FTW!
T
--
Tell me and I forget. Teach me and I remember. Involve me and I understand. -- Benjamin Franklin
More information about the Digitalmars-d
mailing list