Skip to content

Have Single and Populated fail instead of skipping #19489

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

chescock
Copy link
Contributor

@chescock chescock commented Jun 4, 2025

Objective

Change the behavior of Single and Populated to fail validation instead of skipping systems. Users who want the skipping behavior can recover it by wrapping them in When<T>.

This is a very controversial change, and there has been a lot of discussion about it! See some discussion on #18504 (comment), which was spun out into #18516, and some later discussion on #18927 (comment).

I'll try to summarize the arguments here so we don't need to repeat all of them in comments, but let me know if I'm missing or misrepresenting anything and I'll try to update the summary. (And maintainers should feel free to update it!)

Pros

  • A failing version of Single is useful for asserting invariants about your model, just as the failing Res parameter is useful.
    If we don't change the behavior here, we may need to offer another way to do that.
  • A consistent story for when systems skip and when they fail is easier to understand.
    Currently users need to remember the behavior separately for each kind of system parameter, but with this change they would know that systems skip if and only if they write When.
  • Once we do resources-as-entities, consistency between Single and Res will be important.
    I expect users to first learn about resources as a separate concept, and later learn that resources are just a special kind of entity. It will be helpful to be able to teach "Res is just a special kind of Single" without needing to qualify "except that it fails instead of skipping".
  • Making the default behavior be loud helps catch bugs.
    Regardless of the failure behavior, Single is more convenient than Query when you know you have exactly one entity, so it will be used when the user expects it never to fail. Most of the uses in the Bevy examples are in this category! If it does fail, then this is something the user didn't expect and we should inform them. If they do want to skip the system at that point, the error message can guide them to add When. And global error handlers can be used to ensure that anything missed still won't crash the game.
  • This is a breaking change, so if we ever want to change it, it's better to change it sooner.
    Most code that uses Bevy hasn't been written yet!

Cons

  • A failing version of Single is unnecessary now that we have fallible systems.
    Users can use an ordinary Query parameter and write a simple let value = query.single()? to get erroring behavior, but there is no concise way to get skipping behavior.
  • Common cases should be simple.
    The skipping behavior is much more useful than the failing behavior, and will be needed more often. We don't want Bevy to have a reputation for requiring useless boilerplate for common tasks!
  • This is too much churn, part 1
    Single is very new, and we should take time to learn how it's being used in practice before making big changes.
  • This is too much churn, part 2
    Single was introduced in 15.0 with the skipping behavior, and was changed to panic in 15.1 with no workaround. This was a major pain for users who had been eager to use the skipping behavior. The skipping behavior was just restored in 16.0, and breaking it again in 17.0 would be really irritating for some of our most enthusiastic users.

Solution

Change the behavior of Single and Populated to fail validation instead of skipping systems.

Wrap them in When where needed to fix tests.

@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide X-Controversial There is active debate or serious implications around merging this PR C-Code-Quality A section of code that is hard to understand or change C-Usability A targeted quality-of-life change that makes Bevy easier to use labels Jun 4, 2025
Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

Unfortunately I think that this is the right call. It's clear, consistent and the error messages will guide users to discover how to do this. If we're loudly failing for resources, we should do the same here.

When<Single<D, F>> isn't that bad to write, and it does make it clearer what's going on.

@alice-i-cecile alice-i-cecile requested review from cart and mockersf June 4, 2025 16:31
@alice-i-cecile
Copy link
Member

#19490 is important for reviewers to consider when deciding how they feel about this behavior.

@alice-i-cecile alice-i-cecile added the S-Needs-SME Decision or review from an SME is required label Jun 4, 2025
@alice-i-cecile alice-i-cecile added this to the 0.17 milestone Jun 4, 2025
@alice-i-cecile alice-i-cecile requested a review from maniwani June 4, 2025 16:45
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 C-Code-Quality A section of code that is hard to understand or change C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-SME Decision or review from an SME is required X-Controversial There is active debate or serious implications around merging this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants