new annotation or pragma to mark functions that are intended to be only used during compile time
Steven Schveighoffer
schveiguy at gmail.com
Thu Feb 20 19:44:37 UTC 2025
On Thursday, 20 February 2025 at 17:42:25 UTC, Ilya wrote:
> 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:
>>
>> ```d
>> 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.
It has not gone anywhere, but if we were to consider a language
change, I'd want to evaluate whether this is a better option,
since it's a de-facto standard.
> I do see a value in not requiring any language changes, but:
> 1. I'm concerned about doing compile time things based on an
> `assert`, which is a run time thing.
At the root this is code generation. Do you want to generate code
or not? Semantic already has to run for CTFE.
> 2. 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.
`assert(__ctfe)` (and `assert(!__ctfe)`) could be in the same
vein as `assert(0)` -- that is, it always evaluates even in
release builds.
>> 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:
>
> ```d
> 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.
Yes, this is a problem with the idea to make it a compiler error.
However, the compiler still does not have to generate code for
`ctonly`, even if we don't make it an error. It can just replace
the call with an `assert(__ctfe)` (or one that produces a nice
message).
>> 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)`.
Yes, you are right. Then again, your attribute has the same
issue, no?
>> 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.
I think with replacing any runtime calls to a ctfe-only function
with an assert, we have basically the best that can be had.
>> 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?
In general we should prefer solutions that don't require changing
syntax/semantics:
- no need to update IDEs/LSP
- no need to change any semantics
- no new attributes to worry about
- if we hook onto a de-facto standard, then existing code is
upgraded automatically.
-Steve
More information about the dip.ideas
mailing list