Determine if CTFE or RT

Mr.Bingo Bingo at Namo.com
Mon Jun 25 05:47:30 UTC 2018


On Monday, 25 June 2018 at 05:14:31 UTC, Jonathan M Davis wrote:
> On Monday, June 25, 2018 05:03:26 Mr.Bingo via 
> Digitalmars-d-learn wrote:
>> The compiler should be easily able to figure out that foo(3) 
>> can be precomputed(ctfe'ed) and do so. It can already do this, 
>> as you say, by forcing enum on it. Why can't the compiler 
>> figure it out directly?
>
> The big problem with that is that determining whether the 
> calculation can be done at compile time or not means solving 
> the halting problem. In general, the only feasible way to do it 
> would be to attempt it for every function call and then give up 
> when something didn't work during CTFE, which would balloon 
> compilation times and likely cause the compiler to run out of 
> memory on a regular basis given how it currently manages memory 
> and how CTFE tends to use a lot of memory.
>
> It was decided ages ago that the best approach to the problem 
> was to use CTFE only when CTFE was actually required. If an 
> expression is used in a context where its value must be known 
> at compile time, then it's evaluated at compile time; 
> otherwise, it isn't. The compiler never attempts CTFE as an 
> optimization or because it thinks that it might be possible to 
> evaluate the value at compile time. As things stand, it should 
> be pretty trivial to be able to look at an expression and 
> determine whether it's evaluated at compile time or not based 
> on how it's used.
>
> If you're looking to have the compiler figure out when to do 
> CTFE based on the fact that an expression could theoretically 
> be evaluated at compile time, or because you want the compiler 
> to optimize using CTFE, then you're going to be disappointed, 
> because that's never how CTFE has worked, and I'd be _very_ 
> surprised if it ever worked any differently.
>
> - Jonathan M Davis


The docs say that CTFE is used only when explicit, I was under 
the impression that it would attempt to optimize functions if 
they could be computed at compile time. The halting problem has 
nothing to do with this. The ctfe engine already complains when 
one recurses to deep, it is not difficult to have a time out 
function that cancels the computation within some user definable 
time limit... and since fail can simply fall through and use the 
rtfe, it is not a big deal.

The problem then, if D can't arbitrarily use ctfe, means that 
there should be a way to force ctfe optionally!

This means that the compiler will force ctfe if the input values 
are known, just like normal but if they are not known then it 
just treats the call as non-ctfe.

so, instead of

enum x = foo(y); // invalid or valid depending on if y is known 
at CT

we have

cast(enum)foo(y)

which, hypothetically of course, would attempt to precompute 
foo(y) as in the first case but if it is not precomputable then 
just calls it at compile time.

So, the above code becomes

static if (ctfeable(y))
     enum x = foo(y);
     return x;         // compile time version ("precomputed")
else
     return foo(y)     // runtime version


The semantic above is defined for something like cast(enum)(might 
be confusing but anything could be used that works better).

hence
auto x = cast(enum)foo(y);

will result in x being an enum if y is an enum(since chaining can 
then occur), else a runtime variable with the return of foo 
calculated at runtime.


So, this has nothing to do with the halting problem. I'm not 
asking for the compiler to do the impossible, I'm asking for a 
notation that combines to different syntaxes in to a composite 
pattern so one can benefit from the other. Don't make it harder 
than it seems, it's a pretty easy concept.

It might even be possible to do this in a template:

import std.stdio;


auto IsCTFE()
{
	if (__ctfe) return true;
	return false;
}

template AutoEnum(alias s)
{
	static if (IsCTFE)
	{
		pragma(msg, "CTFE!");
		alias AutoEnum = s;
	}
	else
	{
		pragma(msg, "RTFE!");
		alias AutoEnum = s;
	}
}


double foo(int x) { return 3.42322*x; }

void main()
{
	int x = 3;
	writeln(AutoEnum!(foo(x)));
}

So, the problem is that if we replace x with 3 the above code is 
executed at compile time(a precomputation).

But the way it is it won't allow it to be computed even at 
runtime! There is no reason that the compiler can't just replace 
the code with `writeln(foo(x));` for RTFE... yet it errors 
*RATHER THAN* default to RTFE!



The simple fix is to allow for the alternative to not try to ctfe 
and just compute the value at runtime.





More information about the Digitalmars-d-learn mailing list