D의 CTFE를 한동안 잘못 그리고 있었어요. 함수가 컴파일 타임 평가에 적합하면, 인자를 아는 곳 어디서든 컴파일러가 알아서 평가해 줄 거라고 생각했거든요. 실제로는 컴파일 타임 값이 꼭 필요한 곳에서만 해요.
import std.stdio;
int sumSquares(int n)
{
if (!__ctfe)
writeln("sumSquares ran at run time");
int total = 0;
foreach (i; 0 .. n)
total += i * i;
return total;
}
enum a = sumSquares(4); // interpreted by the compiler
immutable b = sumSquares(4); // module scope, also compile time
void main()
{
auto c = sumSquares(4); // ordinary call, prints the line
writeln(a, " ", b, " ", c);
}
이 코드는 c에서 런타임 줄을 한 번 찍고 그다음 14 14 14를 출력해요. enum과 모듈 수준 immutable은 둘 다 컴파일 중에 값이 있어야 하니까 거기서 sumSquares가 해석되고 __ctfe가 참이에요. main 안의 auto는 그냥 평범한 호출이에요. 같은 함수가 같은 인자로 방금 두 번이나 해석됐는데도요.
이제 정리하다가 그 auto를 enum으로 바꾼다고 해 봐요. 호출부에서 바뀌는 건 키워드 하나뿐인데, 함수에는 인터프리터가 전부 실행할 수 있어야 한다는 새 요구 조건이 조용히 붙어요. 읽는 사람이 받는 표시가 정말 선언 키워드 하나뿐인가요?
영어에서 번역·원문 보기Had D's CTFE pictured wrong for a while. I assumed that once a function is fit for compile time evaluation, the compiler would just do it wherever the arguments are known. It does it only where a compile time value is required.
import std.stdio;
int sumSquares(int n)
{
if (!__ctfe)
writeln("sumSquares ran at run time");
int total = 0;
foreach (i; 0 .. n)
total += i * i;
return total;
}
enum a = sumSquares(4); // interpreted by the compiler
immutable b = sumSquares(4); // module scope, also compile time
void main()
{
auto c = sumSquares(4); // ordinary call, prints the line
writeln(a, " ", b, " ", c);
}
This prints the run time line once, from c, then 14 14 14. The enum and the module level immutable both need their value during compilation, so sumSquares is interpreted there and __ctfe is true. The auto in main is an ordinary call, even though the same function with the same argument was just interpreted twice.
Now replace that auto with an enum during some tidy-up. Nothing at the call changes except one keyword, and the function has quietly taken on a new requirement, that the interpreter can run all of it. Is the declaration keyword really the only marker a reader gets?