-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ability to mark functions as wanting to be comptime if possible #425
Comments
I was going to propose something along these lines, where you could mark a function as either optionally comptime or must be comptime. I also didn't know which syntax would be best for these scenarios. Something like: Eager comptime:
and enforced comptime
|
For assert, what about just marking it inline? Then the caller will get |
export fn foo() {
unreachable;
} compiles fine currently. Should this be a compile error? "control flow guaranteed to hit unreachable code" if so then I really like the idea that marking which maybe we want, because sometimes LLVM doesn't inline even when we put always_inline attribute on. I made this an error, but it's kind of like a hopeless, welp, it didn't work, nothing zig can do about it, kind of error. |
"control flow guaranteed to hit unreachable code" sounds like the halting problem. What about a function that unconditionally hits unreachable but that's called conditionally? I think inline is a red herring. Let's go back to the original proposal. Can you give an example of code that shows this issue? i can imagine cases where we do want to generate
|
I sat in on a live stream @andrewrk did last week and had some thoughts about this. IIRC the state of comptime at this time (or at least at the time of the stream) is that a block or function at the call site can be marked as comptime. This is good and I like that it's 100% explicit, however it may become overly verbose in the case of something like assert. Continuing down this line of thinking, we'd like to be able to mark functions as being run at compile time - a reasonable ask. I believe that there's an argument to be made for having a pair of keywords for this. One keyword says "Mr zig compiler, please only ever run this function at compile time", while the other keyword says "Run this at compile time if possible, but also generate a runtime counterpart". With the assert example in mind we would end up with two functions, The reason I propose this is a bug I thought about that it guards against. Imagine we're doing compile time string hashing. If our string hash function accidentally gets passed a runtime string in a place we're expecting it to be passed a const string we're going to have a performance bug. Similarly, if a single assert function worked both at runtime and compile time, there's a chance we would accidentally pass it a runtime value, compile fine, then be oblivious to the fact we may have a bug in that path. I particularly think the assert case is a compelling reason to have at least a way of saying "only ever run this at compile time", but it would be convenient to have both to sometimes avoid code duplication. Not sure if this is a useful idea, or already solved in some other way, but I thought it would be worthwhile sharing. Cheers, |
Marking comptime functions in this fashion seems to me to be similar to marking them inline. We don't have an "inline if you can but otherwise just roll with it" keyword either. I'm not convinced of the need for that, since I imagine the optimizer will probably inline it wherever it makes sense to do so for performance if it can anyway. The same is probably true of comptime. So if we were to match the status quo for inline, then marking a function comptime asserts that it will be run at compile time. If you want it to be either, then write it so it can be run at compile time but don't mark it, and leave it up to the caller to explicitly say they want comptime. Alternatively, instead of adding keywords I think it would make sense to use keyword parameters to state intent. |
It had the downside of running all the comptime blocks and resolving all the usingnamespaces of each system, when just trying to discover if the current system is a particular one. For Darwin, where it's nice to use `std.Target.current.isDarwin()`, this demonstrates the utility that #425 would provide.
If I have to guess whether any given assert(cond); in my code could be executed at either comp or run time, I'll be more likely to get confused about what invariants are present and make mistakes difficult to diagnose. Better to make it explicit. comptime assert(cond); is flexible and communicates intent exactly. But there is value is specifying that a function should always be comptime executed by way of the qualifier. |
All four of these can be represented in fewer characters with expressions, which will be guaranteed to happen at compile-time, and have the same or better precision. The other math constants here which depend on function calls could be similarly removed if and when #425 is solved. However I left them for now since Zig does not eagerly evaluate functions with comptime parameters.
I'm pretty sure what you're wanting is similar to this talk https://www.youtube.com/watch?v=bIc5ZxFL198 |
Another idea would be to add a fn foo() callconv(.Comptime) void {
} which is imho the most "natural" extension. A |
That's definitely an improvement over my suggestion. I second that :) |
@MasterQ32 but how exactly this calling convention works? Are any runtime side effects allowed? (Does this work like comptime in the global scope?) The original proposal is for 'functions eager to be comptime', its a 'transitive comptime' property if all arguments are comptime => do a comptime function call. |
More insight on this issue being closed: After discussing this for a while at a design meeting, we were unable to come up with a satisfactory solution for the "comptime if possible, otherwise runtime" case. Closing this issue does not preclude a future proposal for such a feature, but for now we are acknowledging this as a limitation of the language. We are not convinced that this use case requires a solution. If you have Real Actual Use Cases for this feature, please open a new issue. |
Should this issue be re-opened until the accepted inline=comptime behavior is implemented? Or should we open another issue for that? |
Four files in the standard library have comments linking to this issue, despite it being now closed: Mentions of
|
/// The return type is `type` to force comptime function call execution. | |
/// TODO: https://github.com/ziglang/zig/issues/425 |
Line 988 in 34671b1
/// TODO: https://github.com/ziglang/zig/issues/425 |
Lines 6 to 8 in 34671b1
/// TODO Nearly all the functions in this namespace would be | |
/// better off if https://github.com/ziglang/zig/issues/425 | |
/// was solved. |
Line 238 in 34671b1
/// TODO: https://github.com/ziglang/zig/issues/425 |
If a successor issue has been created, I presume those comments should be updated to point to that issue. Alternatively, if you think this use-case will never be addressed, those comments should be removed.
The halting problem is to create a single algorithm that can determine whether any given TM halts. Contrary to common belief, the unsolvability of the halting problem has no practical implications. Even if it were solvable, there would be TMs for which the analysis would take a very long time, so in any case there has to be a time cutoff when you give up and say that you can't determine whether the code halts. But there are vastly many pieces of code for which it is easy to determine whether they terminate. It's particularly easy for empty code, which is what we have here between |
I have dozens--heading toward hundreds--of functions that always operate at comptime and they all have to be explicitly qualified with comptime at the call site and every one is a potential bug ... so I have changed them to return a type (a struct with a const containing the actual value) or |
This issue is closed, but in
What's the status? Should the comment be removed? |
I came across this too. |
I gave up on my generic library and then on Zig itself because of its wrongheaded approach to comptime -- it doesn't allow marking a function as returning comptime except for magic types like comptime_int, it doesn't allow making comptime part of a type, it doesn't allow making code conditional on whether its being run at comptime ... I explained in my comment above and at #868 why this is a problem. |
Removes a comment referencing #425 which has been closed
Removes a comment referencing ziglang#425 which has been closed
GitHub issue ziglang#425 has been closed and this cleans up remaining code that was written when that issue was open.
GitHub issue ziglang#425 has been closed and this cleans up remaining code that was written when that issue was open.
Since ziglang#425 is closed, changes in this pr are now valid
Use case: if the parameter to
assert
is comptime known, we for sure want to execute the assert function call at compile-time. It would catch a lot of bugs at compile-time instead of generating, essentiallyassert(false)
in some places.So here's a proposal to have a way to mark a function as "eager to be comptime", which means that if all parameters are comptime known, the compiler executes the function and uses the result instead of emitting a runtime function call.
We can't have all functions do this, because functions can contain runtime side effects even if all params are comptime known, and we do want to have compile errors for hitting runtime side effects at compile time for these kind of functions. Case in point, we want the
if (!ok) unreachable
to be a compile-error in the assert function if ok is false. So this is why the user has to mark a function as "eager to be run at compile time".Here's one syntax proposal:
The thing I don't like about this is it looks like
assert
always has to be run at compile-time, but it doesn't. It also looks like you have to mark a functioncomptime
before you can use it at compile-time, and that's also not true.The text was updated successfully, but these errors were encountered: