strange CFTE issue

ag0aep6g via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Mar 15 10:21:09 PDT 2017


On 03/15/2017 02:00 PM, Inquie wrote:
> 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.

The enum array is similar to an AliasSeq in that you can them both in 
contexts that require compile-time constants. But that doesn't mean that 
every context in which you put them gets evaluated at compile time.

Different example: If you write `if (true)` that's a run-time 
conditional even though `true` is a constant. By the language rules, the 
check is done at run time. It may of course be optimized out, but the 
language doesn't care about that. There's also a `static if`. If you 
write `static if (true)`, that check is done at compile time, by the 
language rules. That means you can only put compile-time constants as 
the condition of a `static if`. In other words, the `static if` forces 
compile-time evaluation of its condition.

This "forcing of compile-time evaluation" is how things work. 
Compile-time evaluation is only attempted when it's forced by the 
context. It's not attempted when run-time evaluation is possible. 
`enum`, `mixin`, and `static if` force compile-time evaluation. With 
`foreach` it's only forced when looping over an AliasSeq, because you 
can't do that at run-time.

As for why this is so: Consider that a run-time loop can take a long 
time (hours, days, ...) even if it's over a constant array. It's 
expected that the generated program runs for a long time. It would be 
surprising if the compilation were to take that long time, just because 
the compiler saw that it's possible.

By the way, I'd love to see an actual `static foreach`, with the 
`static` keyword. I'd have it work similar to `static if` and force 
compile-time semantics. Then (slowly) deprecate using plain `foreach` on 
AliasSeqs. Would make D code clearer, in my opinion. But this might have 
non-obvious issues. I haven't thought too hard about it.

[...]
> 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.

It would make a difference with the hypothetical `static foreach`, which 
would accept the first one but reject the second one.

With plain `foreach` it doesn't matter. Ignoring the body, the loop can 
be done at run-time in both versions, so that's what the compiler tries 
to do. Compile-time evaluation must be requested by the programmer. The 
compiler doesn't attempt it eagerly.

> Essentially what you are saying is that if I were to have Methods!
> return an AliasSeq then it would work.

Yup.

> It is a CTFE that returns an
> array.

You might use the term "CTFE" correctly here, but you also might use it 
incorrectly. Just to clarify the term, if `Methods` looks this:

     template Methods(T) { enum Methods = /* ... whatever ... */; }

or like this:

     enum Methods(T) = /* ... whatever ... */;

then it's not a function, but a template. CTFE may happen in the 
"whatever" part, but `Methods` itself does not go through CTFE as it's 
not a function.

But if `Methods` looks like this:

     string[] Methods(T)() { /* ... whatever ... */ }

then it is a function and does go through CTFE.

> 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?

Phobos has it: std.meta.aliasSeqOf "converts an input range [...] to an 
alias sequence." [1]

Applied to your code:

     enum X = ["int foo;", "double bar;"];
     foreach(x; aliasSeqOf!X)
     {
         mixin(x); /* works */
     }

> 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.

Yeah, no. A compile-time constant being used doesn't mean anything. It's 
the context in which it is used that forces compile-time evaluation.


More information about the Digitalmars-d-learn mailing list