On 03/15/2017 03:01 AM, Inquie wrote:
If I do something like
enum X = Methods!(C);
foreach(x; X)
{
mixin(x);
}
I get an error about x not being a compile time variable. (code above is
simplified, the error has nothing to do with the form but of the
foreach(x )
"Compile time variable" may be misleading here. The compiler does not
try to figure out what values are actually constant at compile time.
Rather, the language defines some specific cases where it's guaranteed
that a value is a compile-time constant. Only then can you use it in
static contexts such as mixins. Other values are rejected, even if they
would turn out be constant on a closer look.
`foreach` is mostly a run-time feature. There is a special case when you
iterate over a "compile-time list" [1] (aka AliasSeq, formerly
TypeTuple). In that case, the loop variable is recognized as a constant.
That variant of `foreach` is also dubbed a "static foreach" (even though
the `static` keyword is not used).
Note that it's not a "static foreach" when you iterate over an array, no
matter if that array is constant at compile time or not.
So this works:
import std.meta: AliasSeq;
foreach (x; AliasSeq!("int foo;", "double bar;")) mixin(x);
But this doesn't:
foreach (x; ["int foo;", "double bar;"]) mixin(x);
This is expected and works as intended. Without the definition of your
`Methods` template, I can't say for sure if you're hitting this or if
something else is going on. But if your `X` is an array, this is it.
but if I wrap it in a function it works
string foo()
{
enum X = Methods!(C);
string y = "";
foreach(x; X)
{
y ~= x;
}
return y;
}
mixin(y);
(I'm assuming that last line should be `mixin(foo());`.)
The return value of `foo` is recognized as a compile-time constant
there, because you call it in a context that forces it. This is called CTFE.
Note that you cannot assign the result of `foo()` to a variable first:
string y = foo(); /* no CTFE */
mixin(y); /* no go */
That's because `y` is a normal variable, which is not a recognized
compile-time constant. The value could of course be evaluated at
compile-time, but the compiler doesn't attempt CTFE opportunistically.
The only diff, of course, is the foreach in the first case mixes in on
each iteration, while in the second it doesn't... but it shouldn't
matter. in both cases x is the same.. and it definitely is a compile
time constant in both.
To the compiler it's not a "compile-time constant" in either of them (in
a rather specific sense of the term "compile-time"). During CTFE,
run-time rules apply. So in `foo`, `x` is a normal variable. The same
rules apply as for actual run-time variables. Only the return value of
`foo` is seen as a compile-time value by the compiler.
You're not the first one who stumbles over this meaning of "compile
time". CTFE happens at compile time, and has "compile time" in the name,
but during CTFE you're actually dealing with "run time" values that
might never see the actual run time. Maybe these things could use some
better names.
[1] https://dlang.org/ctarguments.html