Description
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:
- type aliases
- nested bundles
What alternative(s) have you considered?
- 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. - We may want a way to opt-out of this; perhaps with an #[allow_duplicate] attribute on specific fields.
- An error, especially at compile time, is better than a warning, as it will either be immediately fixed or permanently ignored.
- 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.