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