strange CFTE issue

Inquie via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Mar 15 06:00:43 PDT 2017


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.








More information about the Digitalmars-d-learn mailing list