On Wednesday, 15 March 2017 at 03:40:42 UTC, ag0aep6g wrote:
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
Thanks, it explains it, but there is one difference. The array is
assigned to an enum, so surely the compiler can figure that out?
It should be similar to AliasSeq. I could probably wrap AliasSeq
around it and it work or convert it to
an AliasSeq. Seems like an issue with the compiler.
Remember, it's
enum X = Methods!(C);
foreach(x; X)
{
mixin(x);
}
and not
string X = Methods!(C);
foreach(x; X)
{
mixin(x);
}
that should be quite difference and the static foreach in the
first case and non-static foreach in the second.
Essentially what you are saying is that if I were to have
Methods! return an AliasSeq then it would work. It is a CTFE that
returns an array. If there is a function that can convert the the
array to an AliasSeq of tuples there should be no problem,
although I don't see how to do that, it should be possible?
But, this all then seems to be skirting the fact that the loop is
still over a compile time constant(enum or AliasSeq, shouldn't
matter) and should work.