Skip to content

Enforce type-uniqueness of Bundles #2387

Closed
@alice-i-cecile

Description

@alice-i-cecile

What problem does this solve or what need does it fill?

Currently, bundles can have fields of duplicate types. For example:

use bevy::prelude::*;

struct Foo(u32);

#[derive(Bundle)
struct Bar{
  foo1: Foo,
  foo2: Foo,
}

compiles with no warning.

However, this behaviour is deeply wrong, and leads to silent, subtle bugs in end user code.
Each field in a bundle represents one component that should be inserted into the final entity, and entities can only have one unique component of each (Rust) type.

Any duplicate components will have their data silently erased by the last field of the same type; wasting work and causing subtle and serious logic bugs. In the demonstrated example, setting the value of foo1 has no effect: it will always be overwritten by foo2.

This problem is particularly rough when working with type aliases (where the problem is not immediately obvious) and nested bundles (where there can be a large number of elided types, and new errors can occur without any change to user code on a new release if more components are added).

What solution would you like?

The #[derive(Bundle) macro should check for duplicated types, and error (ideally at compile time) if they are found with an error message that displays both the field and type names.

Be sure to test that this check works with:

  1. type aliases
  2. nested bundles

What alternative(s) have you considered?

  1. This could be enforced at component-insertion time, using Command error handling #2241. I would prefer to leave that as an additional layer of opt-in safety, and instead provide compile time checks for obvious mistakes.
  2. We may want a way to opt-out of this; perhaps with an #[allow_duplicate] attribute on specific fields.
  3. An error, especially at compile time, is better than a warning, as it will either be immediately fixed or permanently ignored.
  4. It is by far more important that this is enforced for the Bundle derive macro, but it might be nice to enforce it on manual impls too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-FeatureA new feature, making something new possibleC-UsabilityA targeted quality-of-life change that makes Bevy easier to use

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions