On Thursday, 20 February 2025 at 15:50:33 UTC, Steven Schveighoffer wrote:
>This has been proposed before, and it doesn't require language changes:
void foo() {
assert(__ctfe);
}
Yes, I've seen that. But did it go anywhere? I think on the thread I've found there are some discussions with no conclusion.
I also found another proposals that are suggesting introducing a new attribute (like I do). But there are also no sign of any activity.
I do see a value in not requiring any language changes, but:
- I'm concerned about doing compile time things based on an
assert
, which is a run time thing. - I think making an attribute is a bit clearer. Like, asserts are supposed to only affect debug builds (well, except for
assert(false)
), but I want this new functionality to work in release builds too. There is nothing that stops me from implementing that, but I don't like that assert's meaning gets another exception.
Basically, this will never work at runtime, only at compile time. It's already used in a lot of D code for things like this.
I agree with the point that existing code could immediately benefit from it. That's great. But there is also the second side of this medal: that could also render some existing code non-compilable. How come? Asserts are run-time, what I'm proposing is a static check, so compile time. Static checks are usually either unsound or incomplete. I prefer to stay on the sound side, so it's doomed to be incomplete, meaning it will reject some examples that are working fine with run-time asserts. Imagine this:
int ctonly(int x) {
assert(__ctfe);
return x+1;
}
int f(int v) {
if (v < 10) {
return ctonly(v);
} else {
return smth_runtime(v);
}
}
void main() {
enum x = f(9); // that's fine, CTFE
auto y = f(10); // that's also fine, f() doesn't call ctonly()
}
This works with runtime assert, but will be rejected by the check.
>The compiler can take this hint as "do not optimize or generate object code for this".
That won't work the same way assert(__ctfe)
works today, see the example above, so you are proposing to change the semantics of assert(__ctfe)
.
The compiler can also decide at code-generation time to have an error if it has tried to call the function, or maybe the mark gets spread to the next level up?
I think it's better to require the user to be explicit about that, otherwise we may end up with skipping code generation of main
:) The only exception is when such function is passed as a template parameter, in this case I believe we need to add some basic inference to make it usable in practice.
It can be very straightforward -- if this is not the first runtime statement in the function, then it doesn't get the benefit. It has to be this form.
Yeah, we can take the shortcut in the implementation and only look at the first statement, but I'm more concerned about changing the semantics.
Why does it have to be this form?