-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
audit use of %% prefix operator in standard library #510
Comments
Here's hello world with this proposal: const io = @import("std").io;
pub fn main() -> %void {
io.stdout.printf("Hello, world!\n") %% unreachable;
} The code in See #511 which I just opened. Until that is done, I think that your proposal of removing the operator is interesting, can you file a separate issue for that which is labeled "proposal" and not "bug"? |
I don't understand how printf is unable to fail in hello world. Wouldn't the following be better: const io = @import("std").io;
pub fn main() -> %void {
%return io.stdout.printf("Hello, world!\n");
} |
Hmm, maybe that is better. |
Are you saying the solution to allocation failure is to ensure memory allocation will always succeed? And that means effectively assuming we have infinite memory, which I'm pretty sure is one of the antipatterns Zig was designed to combat. |
The other reason I used Related, I think it might be interesting to explore if we can have the ability to collect a stack trace very quickly, and at least in debug mode and maybe also in release-safe mode, collect stack traces when an error is returned from a function, and attach them to the error. Then if you had to debug an error when it was passed around via |
I remember one reason In release fast mode, whereas in C you'd have a straightforward series of calls to printf, in zig you'd have a branch for each one. Maybe you kind of want undefined behavior or a crash if printf fails. Maybe. In practice I think printing to stdout or stderr is not a bottleneck, and the branches would be fine, especially with #84. Also, maybe we don't aim the shotgun at one's feet automatically. Users can always make their own shotgun with: pub fn out(comptime format: []const u8, args: ...) {
io.stdout.printf(format, args) %% unreachable;
} |
One more reason test "aoeu" {
%%foo();
}
error ItBroke;
fn foo() -> %void {
return error.ItBroke;
}
vs test "aoeu" {
foo() %% unreachable;
}
The former has a better debugging experience because you get the error string printed. Maybe we can look for this pattern and codegen it the same way. |
But
I'll bring this up again. Even |
Actually yes. This is a bit of a special case. build.zig is built when someone does |
Ok, so what this means is that we've got two different ways of writing Zig code.
The latter category includes build scripts and tests, where the Are we comfortable with this dichotomy? Isn't this a pretty big violation of one-obvious-way? What if we change tests to return errors to signal failure instead of hitting |
https://github.com/zig-lang/zig/blob/a458ec9998159dcfcbb013c6202bdd123969dfaf/std/debug.zig#L14-L24 |
So we want 2 ways to write zig code? Like a project can specify in it's readme that it relies on safety, so you gotta build with safety enabled to use the library properly? Wouldn't it make a lot more sense for there to only be one way to write zig code? |
There are not 2 ways to write zig code. The
I got it working at all, and now it can be improved. |
I updated the hello world examples, and I made the C version do the same error checking so that the comparison is fair. |
If I understand the solution correctly, tests must always use |
That is correct. Although maybe this ok, because presumably you already tested in debug mode, and you have actual assertions you want to test as well. As an alternative to One could implement a helper in userland: fn ok(x: var) -> @typeOf(x).ChildType {
return x %% |err| @panic("test failed: {}", err);
}
test "foo" {
const cwd = ok(os.getCwd(&debug.global_allocator));
assert(cwd[0] == '/');
} |
or we change the implicit return type of and then we remove the special case from fn assertOrError(b: bool) -> %void {
if (!b) return error.AssertionFailure;
} then tests call now there's no special cases for test mode, and tests look like production code wrt undefined behavior. there is a functional improvement in this change i'm proposing, which is that it is no longer appropriate for tests to get coverage on assertion failures in the production code. In my opinion assertion failures should be impossible to hit from the api, and so it doesn't make sense to test them. |
Getting rid of the special case in The only problem I have with |
Stack traces are generally useful things, especially in error situations. I'm a little bit nervous going in the direction of attaching stack traces to errors, because it's a slippery slope. What's next? Error messages? How about transplanting the stack trace when an error handler returns a different error? Seems like an opportunity for innovation, but I don't have any good ideas at the moment. |
My two cents is that writing to a file descriptor can fail at runtime so %% should terminate execution and not be undefined or not be encouraged in the documentation for this use case. I can see two things being mixed, wanting to ignore (yet still fail early) from a problem that should never really happen, and wanting to get performance from truly impossible situations. |
e.g. https://github.com/zig-lang/zig/blob/5e6fc94b7f43dda028de779a874f12591fa0a50d/std/build.zig#L89
The
%%
prefix operator is supposed to mean that something is impossible, not that it's an error to happen. The above link is possible at runtime if the user passes in longbuild_root
andcache_root
parameters, and then the allocator runs out of memory while concatenating them. That's not impossible; that's an error.I'm generally uneasy about
%%foo()
being easier to type than%return foo()
. It seems that%return foo()
should be more commonly used than%%foo()
, so why is it harder to type? If the author isn't certain whether an error is possible or not, then use%return
(or do more research and become certain). Only when the author is certain despite the Zig type system that an error is not possible is it appropriate to use the%%
prefix operator.Should we remove
%%foo()
and just let the user typefoo() %% unreachable
instead?The text was updated successfully, but these errors were encountered: