Skip to content

Conversation

@joseph-gio
Copy link
Member

@joseph-gio joseph-gio commented Jan 25, 2026

Objective

We include several run condition combinators, such as and, or, etc., which short-circuit depending on the output of the first condition in the combinator.

This is incredibly error-prone due to the subtle way that short-circuiting interacts with change detection -- rather than reacting to changes frame-by-frame, the second condition in short-circuiting combinator will react to the last time that the first condition did not short circuit. This can easily lead to confusing bugs if the user does not expect this, and I suspect that most users will not expect this.
For this reason, when combining multiple run conditions added via .run_if(), all run conditions are intentionally eagerly evaluated.

Solution

Add new run condition combinators and_then, and_eager, or_else, or_eager, etc., for clarity, and deprecate the previous methods, pointing users to the new ones.

After the previous combinators have been removed for a few release cycles, we should consider renaming combinators such as and_eager to simply and.

Migration Guide

Bevy supports run condition combinators (and, or, nan, nor), which have historically short-circuited. While familiar, short-circuiting interacts with Bevy’s change detection in a subtle way: when the left-hand condition short-circuits, the right-hand condition is not evaluated and therefore does not observe changes on that frame. Instead, it reacts based on the last frame it ran, which can lead to confusing and non-local bugs.

By contrast, Bevy's scheduler combines multiple .run_if(...) conditions using eager evaluation, which avoids this known pitfall.

To make intent explicit and reduce footguns, short-circuiting combinators have been renamed and eagerly-evaluated variants have been added.

Examples

Most users should use eager evaluation, which ensures all conditions participate in change detection every frame:

// Before (deprecated)
cond_a.and(cond_b)
cond_a.or(cond_b)
cond_a.nand(cond_b)
cond_a.nor(cond_b)

// After (recommended default)
cond_a.and_eager(cond_b)
cond_a.or_eager(cond_b)
cond_a.nand_eager(cond_b)
cond_a.nor_eager(cond_b)

If you intentionally rely on short-circuiting for correctness, use the explicit short-circuiting variants:

// Explicit short-circuiting
cond_a.and_then(cond_b)
cond_a.or_else(cond_b)
cond_a.nand_then(cond_b)
cond_a.nor_else(cond_b)

xor and xnor are unchanged, as they cannot short-circuit by nature.

Future naming note

The _eager suffix exists to ease migration without changing the behavior of existing code that relied on short-circuiting. After the deprecated combinators have been removed for a few release cycles, we expect to revisit naming and likely remove the _eager suffix, keeping and_then / or_else as the explicit short-circuiting forms.

@joseph-gio joseph-gio added the A-ECS Entities, components, systems, and events label Jan 25, 2026
@alice-i-cecile alice-i-cecile added C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide X-Contentious There are nontrivial implications that should be thought through S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jan 25, 2026
@joseph-gio
Copy link
Member Author

joseph-gio commented Jan 25, 2026

I don't really agree that this is contentious -- even if the exact solution used in this PR isn't the desired path forward, fixing the change detection footgun seems necessary to me. The current behavior is way too subtle and counterintuitive to be the default.

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.

A short migration guide is required, but I really like the proposed migration strategy, and the names are solid. Once that's done, you'll have my approval. I agree in principal, so I'll mark this as X-Blessed.

@alice-i-cecile alice-i-cecile added X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers and removed X-Contentious There are nontrivial implications that should be thought through labels Jan 25, 2026
@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 and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jan 26, 2026
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-Usability A targeted quality-of-life change that makes Bevy easier to use M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants