-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Tracking issue: Replace unwrap
with expect
#3899
Comments
When you need to capture state in the error message, use |
I'm interested in this as a first contribution. Should this be tackled as one PR, or one PR per crate? |
Awesome! Thank you <3 Great to have you here!
I would suggest making one PR per crate so that reviewing the changes and getting them merged is easier. You could also compile 2-3 crates into one PR if the crates don't have a lot of |
Okay cool, thanks! I'll start with with |
Perfect! Thank you :) I just checked |
I don't think replacing all Also, when possible, please add to the error codes (https://github.com/bevyengine/bevy/tree/main/errors) when adding an error message. |
Thanks for the suggestions and your explanation in the bevy discord! I updated the description accordingly. |
Hey, I'm looking for a first contribution as well. Is it okay if I start with a couple of crates on this issue as well, or do you want all of them? In that case I'll look for a different issue. (But this seems good in scope and to get to grips with a repo of this scale, even at work we're nowhere close to this size of a code base ^^) |
Yes please! Just let us know which ones you would like to tackle. |
Welcome! I answered the same question in a previous comment of mine (see below).
|
Another suggestion: expect message on an |
Good call! Added this to the description as well. |
Hi ! My friend and I want to tackle the unwraps in |
Welcome! Yes of course. The |
I'd like to take bevy_log |
We've checked the unwraps in the bevy_input crate and we only found these. Is it necessary to change those to expects ? In this case unwrap seems to be appropriate.
|
@Laozey that's correct, those are fine. Unwrap_or variants also don't have the same problems as bare unwraps either. |
@Laozey True. Like @alice-i-cecile already said |
Taking the |
Is there any crates that are still not tackled that I can start working on as a first contribution? |
Can I claim the bevy_pbr crate.? I can see it has a lot of unwraps and no one seems to claim it? |
@mnmaita Yup, that's absolutely fine. Thank you!
@omarbassam88 I have a list of every crate in the description of this issue and also if they are done (marked by the checkbox) or already claimed (mentioned in parenthesis after the crate name). You can start working on any crate that isn't done or claimed yet, but please let us know which ones you decide to do so we avoid having multiple PR's that work on the same crate. |
@omarbassam88 Of course! It's not done or claimed yet. Thanks for the help :) |
IMO we need a unified error message for these PRs for "resource not found". Or, perhaps more usefully, a common error type that is returned and unwrapped. "Could not find resource" isn't actually more helpful than an unwrap unfortunately. |
Please do not continue working on this tracking issue for now. The reason for this is mentioned at the top of the issue description! |
Something to consider before throwing expects onto more "internal" non-user facing code: static strings are compiled into the binary. I don't think we want to bloat bevy apps with a bunch of "internal error messages", especially in cases where the context of the code is as good (if not better) for debugging than the message in the expect (for a Bevy Engine dev debugging a user-reported error). |
I think we should consider only using expect messages for "panics that are in normal user-facing dev-flows" |
# Objective - In the large majority of cases, users were calling `.unwrap()` immediately after `.get_resource`. - Attempting to add more helpful error messages here resulted in endless manual boilerplate (see #3899 and the linked PRs). ## Solution - Add an infallible variant named `.resource` and so on. - Use these infallible variants over `.get_resource().unwrap()` across the code base. ## Notes I did not provide equivalent methods on `WorldCell`, in favor of removing it entirely in #3939. ## Migration Guide Infallible variants of `.get_resource` have been added that implicitly panic, rather than needing to be unwrapped. Replace `world.get_resource::<Foo>().unwrap()` with `world.resource::<Foo>()`. ## Impact - `.unwrap` search results before: 1084 - `.unwrap` search results after: 942 - internal `unwrap_or_else` calls added: 4 - trivial unwrap calls removed from tests and code: 146 - uses of the new `try_get_resource` API: 11 - percentage of the time the unwrapping API was used internally: 93%
Yep: IMO APIs like that should just unwrap a good error type, or have an infallible version. |
Yeah seems reasonable. If we think there is value in adding an error message inside of internal stuff, should that be done using Example:
Yeah this should definitely be our main goal, but I also think there is great value in having helpful error messages inside of the internal code. Obviously only to an extend, but this could really make the life of new or inexperienced contributors easier.
Agreed. Good error types should be one of the main takeaways of this tracking issue. Your |
- In the large majority of cases, users were calling `.unwrap()` immediately after `.get_resource`. - Attempting to add more helpful error messages here resulted in endless manual boilerplate (see bevyengine#3899 and the linked PRs). - Add an infallible variant named `.resource` and so on. - Use these infallible variants over `.get_resource().unwrap()` across the code base. I did not provide equivalent methods on `WorldCell`, in favor of removing it entirely in bevyengine#3939. Infallible variants of `.get_resource` have been added that implicitly panic, rather than needing to be unwrapped. Replace `world.get_resource::<Foo>().unwrap()` with `world.resource::<Foo>()`. - `.unwrap` search results before: 1084 - `.unwrap` search results after: 942 - internal `unwrap_or_else` calls added: 4 - trivial unwrap calls removed from tests and code: 146 - uses of the new `try_get_resource` API: 11 - percentage of the time the unwrapping API was used internally: 93%
I updated the description of the tracking issue and added a new |
unwrap_or_else would still suffer from the same problem, as that function would still have the string compiled into the binary. If you see a "string literal" in rust code, that will be added to the binary. An alternative here that is almost as good from a debugging perspective: continue using unwraps for "non-user-facing internal errors", but add a comment above them explaining why the unwrap is ok. People debugging internal errors will have the code in front of them anyway.
This won't fit every situation. For improving something like an "internal option unwrap", a "good error type" would still involve defining string literals for each error variant, plus the additional complexity of mapping that option to the error type. Creating an infallible version just "moves" the problem somewhere else (and adds implementation complexity). Imo there will always be class of thing that gets worse by using those approaches. I think I prefer "comments above I also think there might be cases where the context of the unwrap is "clear enough" to someone looking at the code. If it ever feels like someone is adding a comment above an unwrap "because its a rule and not because it adds clarity", we should push back. |
That's solid advice. I think we should close out this issue (and the linked PRs), and add this advice to the style guide. |
Yeah that'll probably work just fine for internal code.
Agreed. This tracking issue sadly cause more harm than good. It was a great learning experience though! |
Explanation
Calling
unwrap
on anOption
orResult
causes the program to panic if theOption
isNone
or theResult
isErr
. If the program panics because of anunwrap
call, the error message isn't really helpful. To help contributors and users of bevy find problems faster we can useexpect
to our advantage. Callingexpect
works exactly the same asunwrap
, but allows us to pass a string containing an explanation of why the panic occurred or rather what weexpect
ed to be the case.Example
Unwrap
Expect
To-Do
Replace most of the
unwrap
s inside of the individual crates with more explanatoryexpect
s. Changing theunwrap
calls inside of our main code is more important than inside of our tests, but it's appreciated if it is done in both.General error handling
Through the PR's made for this tracking issue we realized that we have a lot of very similar and common error messages that all have to stay consistent for a good user and developer experience. Since this is hard to maintain we want to introduce better error handling in general for things like getting a resource (#4047).
If you realize that in one of your PR's you are writing the same error message multiple times, you might as well consider doing something similar to #4047 and create better error handling for those things.
Invariants
Not every
unwrap
call should be replaced withexpect
. This is because sometimesunwrap
is used on an invariant. An invariant is something that doesn't vary and can therefore be assumed to always successfullyunwrap
without panicking.Error codes
Whenever possible and reasonable please add the error to the error codes when adding an error message. This should only be done for errors that can't be explained in a single line and therefore need a more in depth explanation of how to fix the error.
No final dot
There shouldn't be a dot at the end of an error message. This is because Rust will add
: Err
at the end of anexpect
error message on aResult
. On anOption
this looks fine, but to keep it consistent don't add a dot there either.Example
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=aed00b15860c0c31534e110ca7852a4d
Crates
bevy_app
(claimed Replace unwraps with expects in bevy_app, bevy_audio, bevy_core, and bevy_core_pipeline #3913)bevy_asset
(claimed Replace unwraps with expects in bevy_asset #3892)bevy_audio
(claimed Replace unwraps with expects in bevy_app, bevy_audio, bevy_core, and bevy_core_pipeline #3913)bevy_core
(claimed Replace unwraps with expects in bevy_app, bevy_audio, bevy_core, and bevy_core_pipeline #3913)bevy_core_pipeline
(claimed Replace unwraps with expects in bevy_app, bevy_audio, bevy_core, and bevy_core_pipeline #3913)bevy_crevice
bevy_derive
(nounwrap
s)bevy_diagnostic
(claimed Replace unwraps with expects in bevy_window, bevy_scene and bevy_diagnostics #3975)bevy_dylib
(nounwrap
s)bevy_dynamic_plugin
(crate get's removed by Remove bevy_dynamic_plugin #3893)bevy_ecs
bevy_ecs_compile_fail_tests
bevy_gilrs
(nounwrap
s)bevy_gltf
bevy_input
(nounwrap
s)bevy_internal
(nounwrap
s)bevy_log
(claimed replace unwrap in bevy_log with expect #3957)bevy_macro_utils
bevy_math
(nounwrap
s)bevy_pbr
(claimed Replace unwraps with expects in bevy_pbr #4046)bevy_reflect
bevy_render
bevy_scene
(claimed Replace unwraps with expects in bevy_window, bevy_scene and bevy_diagnostics #3975)bevy_sprite
(claimed Replaceunwrap
calls withexpect
inbevy_sprite
crate #4043)bevy_tasks
bevy_text
bevy_transform
bevy_ui
bevy_utils
(nounwrap
s)bevy_window
(claimed Replace unwraps with expects in bevy_window, bevy_scene and bevy_diagnostics #3975)bevy_winit
The text was updated successfully, but these errors were encountered: