Skip to content

Make Query::single (and friends) return a Result #18082

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

Merged
merged 13 commits into from
Mar 2, 2025

Conversation

alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Feb 27, 2025

Objective

As discussed in #14275, Bevy is currently too prone to panic, and makes the easy / beginner-friendly way to do a large number of operations just to panic on failure.

This is seriously frustrating in library code, but also slows down development, as many of the Query::single panics can actually safely be an early return (these panics are often due to a small ordering issue or a change in game state.

More critically, in most "finished" products, panics are unacceptable: any unexpected failures should be handled elsewhere. That's where the new

With the advent of good system error handling, we can now remove this.

Note: I was instrumental in a) introducing this idea in the first place and b) pushing to make the panicking variant the default. The introduction of both let else statements in Rust and the fancy system error handling work in 0.16 have changed my mind on the right balance here.

Solution

  1. Make Query::single and Query::single_mut (and other random related methods) return a Result.
  2. Handle all of Bevy's internal usage of these APIs.
  3. Deprecate Query::get_single and friends, since we've moved their functionality to the nice names.
  4. Add detailed advice on how to best handle these errors.

Generally I like the diff here, although get_single().unwrap() in tests is a bit of a downgrade.

Testing

I've done a global search for .single to track down any missed deprecated usages.

As to whether or not all the migrations were successful, that's what CI is for :)

Future work

Rename Query::get_single and friends to Query::single!

I've opted not to do this in this PR, and smear it across two releases in order to ease the migration. Successive deprecations are much easier to manage than the semantics and types shifting under your feet.

Cart has convinced me to change my mind on this; see #18082 (comment).

Migration guide

Query::single, Query::single_mut and their QueryState equivalents now return a Result. Generally, you'll want to:

  1. Use Bevy 0.16's system error handling to return a Result using the ? operator.
  2. Use a let else Ok(data) block to early return if it's an expected failure.
  3. Use unwrap() or Ok destructuring inside of tests.

The old Query::get_single (etc) methods which did this have been deprecated.

@alice-i-cecile alice-i-cecile added this to the 0.16 milestone Feb 27, 2025
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events X-Controversial There is active debate or serious implications around merging this PR S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 27, 2025
@alice-i-cecile alice-i-cecile requested a review from cart February 27, 2025 23:05
@alice-i-cecile alice-i-cecile added the D-Straightforward Simple bug fixes and API improvements, docs, test and examples label Feb 27, 2025
Copy link
Contributor

@bushrat011899 bushrat011899 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good direction for the engine. I look forward to reclaiming those names so get_single can just be single in 0.17.

Comment on lines 158 to 160
let mut camera_transform = camera_query.single_mut();
let Ok(mut camera_transform) = camera_query.get_single_mut() else {
return;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the signature for move_camera not be changed to return Result, allowing the use of ? here too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but this is an example of a case where silently failing and just returning is always correct. You never want to panic here.

assert_eq!(entity_a, query_a.single(&world));
assert_eq!(entity_a, query_a.get_single(&world).unwrap());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I prefer to wrap the reference value in Ok(...) rather an unwrap in an assert_eq, as that will print a nicer error message. Has the same end-result of failing the test so it's not that big of a deal though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, mildly agree.

@alice-i-cecile alice-i-cecile requested a review from cart February 28, 2025 00:51
/// fn my_system(query: Query<&A>, mut commands: Commands) {
/// match query.single() {
/// Ok(a) => (), // Do something with `a`
/// Err(err) => match err {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like these docs!

Copy link
Contributor

@Carter0 Carter0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im a fan!

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward X-Controversial There is active debate or serious implications around merging this PR labels Feb 28, 2025
@alice-i-cecile
Copy link
Member Author

I still need to fix CI, but once that's done I'm going to call this good to merge.

@alice-i-cecile alice-i-cecile changed the title Deprecate Query::single Make Query::single (and friends) return a Result Feb 28, 2025
@IQuick143 IQuick143 added the M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide label Feb 28, 2025
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Mar 2, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Mar 2, 2025
Merged via the queue into bevyengine:main with commit 2ad5908 Mar 2, 2025
31 checks passed
github-merge-queue bot pushed a commit that referenced this pull request Mar 7, 2025
# Objective

Alternative to and closes #18120.

Sibling to #18082, see that PR for broader reasoning.

Folks weren't sold on the name `many` (get_many is clearer, and this is
rare), and that PR is much more complex.

## Solution

- Simply deprecate `Query::many` and `Query::many_mut`
- Clean up internal usages

Mentions of this in the docs can wait until it's fully removed in the
0.17 cycle IMO: it's much easier to catch the problems when doing that.

## Testing

CI!

## Migration Guide

`Query::many` and `Query::many_mut` have been deprecated to reduce
panics and API duplication. Use `Query::get_many` and
`Query::get_many_mut` instead, and handle the `Result`.

---------

Co-authored-by: Chris Russell <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events D-Straightforward Simple bug fixes and API improvements, docs, test and examples M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants