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

Reply via email to