On Sunday, 23 February 2025 at 17:07:30 UTC, Ilya wrote:
>On Friday, 21 February 2025 at 14:04:41 UTC, Steven Schveighoffer wrote:
>Paul Backus pointed out on discord, there is a very large problem with this mechanism:
importing a file with a function that is not a template nor an auto function means the semantic is skipped for that function. This means it would be impossible to know that this function is ctfe-only. The only other solution there is to semantic every function, which basically negates any wins we get from not optimizing these functions.
Yes, that's a good point, thanks.
>So reading all the responses here, my impression is:
- I think it's a necessary idea to have an attribute if we want this feature. I like using
@__ctfe
as this requires no new syntax, and actually already compiles (it just doesn't do the thing expected). What remains to be seen is if we can hook this properly.@__ctfe
becomes@(true)
currently. If not, then a new attribute is trivial to add to core.attributes.
I've already updated our internal version to use @__ctfe
, it works just fine.
- If we are going to have a mechanism to flag that code generation should be avoided, it would be good to also do this for functions that begin with
assert(__ctfe)
. This at least helps with existing uses of that mechanism.
As I said in another reply, I think it can't (and shouldn't) be a plugin replacement for assert(__ctfe)
. But we can do a small migration tool.
- I don't agree with the compiler errors for all uses of ctfe-only functions at runtime. As you pointed out, this can be valid for cases. I don't think it's worth the headache, and I have learned in the past not to pre-optimize for rule following especially in generic code. Just let the thing happen as it would.
Oh, so you are saying we will have to add an attribute (because of compiler implementation reasons), but we'll make it work as if it's an assert(__ctfe)
in the first line anyway?
I don't agree here. Static check allows us to simply drop these functions, without having to rewrite call sites, it plugs naturally into existing skipCodegen
implementation and it provides faster feedback, helping to set the attributes correctly. It also lets dropping more functions, think templates. If you use map!ctonly(xs)
, there is no point to codegen MapResult!(ctonly, xs).front
for example.
The check will reject some code that could be written with asserts, that's correct. But I don't see it as a problem. It's like static vs dynamic types. You can't put a string into an int in a typed language, but in Python you can. Does it make typed languages worse? I'm not sure.
Since we are adding a new annotation, let's make it right. Such that we are absolutely sure we can omit the codegen and no surprises will happen in run time. And if someone wants to have a contrived behavior, like the one in my example, they are welcome to continue using asserts. We are not going to deprecate assert(__ctfe)
, right?
- To that end, calling a known ctfe-only function should result in an appropriate
assert(false, "cannot call ctfe-only function blahblah at runtime")
when doing code generation instead of the call to a non-existent function that has a linker error.
I honestly prefer a linker error over a run-time assert :) Sounds like a time bomb.
There are people out there which can't read linker errors, contrary to that, I believe that an advanced feature anyway. To be fair, nowadays, I understand them enough for that. Maybe we could implement that behavior of no-codegen vs a stub with assert(false) with the same strategy as -check=
.
Since assert(__ctfe
) is existing code, I would say that, implementations that skip codegen because of assert(__ctfe)
, we could instead, we could do like -ctfeskip=stub
and -ctfeskip=yes
or something like that.
While @__ctfe
would altogether trigger the same behavior as no codegen at all, like -ctfeskip=yes
.
That would bring:
- More control to one which understand what they're doing by using either
@__ctfe
and-ctfeskip=yes
. - Benefits existing code
- Avoid breaking existing code since the default could be using the stub.