bevy/release-content/migration-guides/generic-option-parameter.md
Chris Russell 9e2bd8ac18
Generic SystemParam impls for Option and Result (#18766)
# Objective

Provide a generic `impl SystemParam for Option<P>` that uses system
parameter validation. This immediately gives useful impls for params
like `EventReader` and `GizmosState` that are defined in terms of `Res`.
It also allows third-party system parameters to be usable with `Option`,
which was previously impossible due to orphan rules.

Note that this is a behavior change for `Option<Single>`. It currently
fails validation if there are multiple matching entities, but with this
change it will pass validation and produce `None`.

Also provide an impl for `Result<P, SystemParamValidationError>`. This
allows systems to inspect the error if necessary, either for bubbling it
up or for checking the `skipped` flag.

Fixes #12634
Fixes #14949
Related to #18516

## Solution

Add generic `SystemParam` impls for `Option` and `Result`, and remove
the impls for specific types.

Update documentation and `fallible_params` example with the new
semantics for `Option<Single>`.
2025-05-07 18:20:08 +00:00

952 B

title pull_requests
Generic `Option` Parameter
18766

Option<Single<D, F>> will now resolve to None if there are multiple entities matching the query. Previously, it would only resolve to None if there were no entities, and would skip the system if there were multiple.

We have introduced a blanket impl SystemParam for Option that resolves to None if the parameter is invalid. This allows third-party system parameters to work with Option, and makes the behavior more consistent.

If you want a system to run when there are no matching entities but skip when there are multiple, you will need to use Query<D, F> and call single() yourself.

// 0.16
fn my_system(single: Option<Single<&Player>>) {
}

// 0.17
fn my_system(query: Query<&Player>) {
    let result = query.single();
    if matches!(r, Err(QuerySingleError(MultipleEntities(_)))) {
        return;
    }
    let single: Option<&Player> = r.ok();
}