Error when having 16 components with the new tuple .spawn(())
Bevy version
bevy = {version = "0.9.1", features = ["dynamic", "wayland"]}
[Optional] Relevant system information
OS: Manjaro Linux x86_64 Kernel: 5.15.85-1-MANJARO
What you did
When creating 16 (different) components and using the new tuple way of spawning .spawn(()), building the project causes an error:
Components:
#[derive(Component)]
struct One;
#[derive(Component)]
struct Two;
#[derive(Component)]
struct Three;
#[derive(Component)]
struct Four;
#[derive(Component)]
struct Five;
#[derive(Component)]
struct Six;
#[derive(Component)]
struct Seven;
#[derive(Component)]
struct Eight;
#[derive(Component)]
struct Nine;
#[derive(Component)]
struct Ten;
#[derive(Component)]
struct Eleven;
#[derive(Component)]
struct Twelve;
#[derive(Component)]
struct Thirteen;
#[derive(Component)]
struct Fourteen;
#[derive(Component)]
struct Fifteen;
Spawning:
commands.spawn((
Name::new("Hi it's me"),
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Eleven,
Twelve,
Thirteen,
Fourteen,
Fifteen
));
Error:
error[E0277]: the trait bound (bevy::prelude::Name, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen): bevy::prelude::Component is not satisfied
The components themselves do not matter, just that there are more than 15 of them:
commands.spawn((
Name::new("Hi it's me"),
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Eleven,
Twelve,
// ...
Fifteen,
Sixteen,
Seventeen,
));
Results in the same error.
However, when using the old way of spawning, .spawn().insert().insert()..., it works fine and compiles.
It also compiles just fine when using one less component, i.e., just until Fourteen.
Old way:
commands
.spawn(Name::new("Hi it's me"))
.insert(One)
.insert(Two)
.insert(Three)
.insert(Four)
.insert(Five)
.insert(Six)
.insert(Seven)
.insert(Eight)
.insert(Nine)
.insert(Ten)
.insert(Eleven)
.insert(Twelve)
.insert(Thirteen)
.insert(Fourteen)
.insert(Fifteen)
.insert(Sixteen)
.insert(Seventeen);
Works fine:

What went wrong
-
what were you expecting? All components to be inserted into the newly spawned object.
-
what actually happened? Only up to 16 components can be loaded using the new tuple way, after that it errors with:
error[E0277]: the trait bound `(bevy::prelude::Name, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen): bevy::prelude::Component` is not satisfied
--> src/main.rs:355:20
|
355 | commands.spawn((
| ______________-----_^
| | |
| | required by a bound introduced by this call
356 | | Name::new("Aye caramba"),
357 | | One,
358 | | Two,
... |
371 | | Fifteen
372 | | ));
| |_____^ the trait `bevy::prelude::Component` is not implemented for `(bevy::prelude::Name, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen)`
|
= help: the following other types implement trait `bevy::prelude::Component`:
AdditionalMassProperties
AlphaMode
Analyzer
AnimationPlayer
AsyncCollider
AsyncSceneCollider
BackgroundColor
Barracks
and 191 others
= note: required for `(bevy::prelude::Name, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen)` to implement `Bundle`
Additional information
The note in the message suggests aligning them into a Bundle, but if it is indeed the solution, then the limit of 16 with the new spawn system should be documented somewhere. However, the fact that there are no errors with the old way of spawning is a bit suspicious.
Shall any more info be required, please let me know.
Thanks for your help!
Bundle is only implemented for tuples of up to 15 elements. however you can circumvent this by nesting the bundles e.g.
commands.spawn((
(
Name::new("Hi it's me"),
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
),
(
Nine,
Ten,
Eleven,
Twelve,
Thirteen,
Fourteen,
Fifteen,
Sixteen,
Seventeen,
),
));
Technically this limit is documented here. A lot of people have this confusion, though, so maybe it's not prominent enough? It could at least talk about the solution @soqb shared. Even though it encourages creating a custom struct for this, it's still good to know if really wanting to not create an additional type.
Thanks all!
@soqb 's way is indeed a quick way to circumvent the issue that I am going to use for now. I think the main weakness point, is that with the old way one can add as many components without any limit (correct me if I'm wrong, in my example it worked with more than 16, but I didn't try to reach an upper limit), while the new way does have this limit. The docs do not mention this limit as far as I checked, so it might be a good idea to add it as another example (or a note, that there is a limit of 16, and one can either implement Bundle, or nest them together).
@MrGVSV : I think that creating a bundle might not be a good solution 100% of the time, because one might not be able to bind together components that might not have anything in common (if the project is large enough).
I think the main weakness point, is that with the old way one can add as many components without any limit (correct me if I'm wrong, in my example it worked with more than 16, but I didn't try to reach an upper limit), while the new way does have this limit.
If by "old" way, you mean using insert, then that's still possible and doesn't have any limit (that I know of). Previously, spawn_bundle required an actual Bundle struct, which doesn't have the 15-max limitation.
The docs do not mention this limit as far as I checked, so it might be a good idea to add it as another example (or a note, that there is a limit of 16, and one can either implement Bundle, or nest them together).
Ah, I see what you mean. While Bundle does explicitly identify this limitation, the docs for Commands::spawn do not. I wonder if that needs to make note of the tuple limit as well or maybe just advise reading the Bundle docs for details/caveats.
@MrGVSV : I think that creating a bundle might not be a good solution 100% of the time, because that can bind together components that might not have anything in common (if the project is large enough).
Sure, but you don't necessarily need to export that type. Just define it locally to that module— or even to the system function— so that it "doesn't exist" as far as the rest of your project is concerned.
@MrGVSV Yes, exactly, you're on point. In the Bundle it says that
Additionally, Tuples of bundles are also Bundle (with up to 15 bundles).
and
Tuple bundles can be nested, which can be used to create an anonymous bundle with more than 15 items.
In Commands::spawn however there is no mention of the limit or the number 15, and that would be the first place where I'd look for the issue, since the error also points to the .spawn(()) and mentions the Bundle on the very bottom of the text.
I think the easiest solution would be to add the note in the .spawn(())'s docs and the example from @soqb explicitly.
Would it be reasonable to have a bundle! macro that automatically nest tuples when needed?
Would it be reasonable to have a
bundle!macro that automatically nest tuples when needed?
Maybe? But it's still something users need to be aware of so that they know when to use such a macro. Learning about this limitation without a macro may help understand other places this crops up, such as with the number of system or query parameters.
Also, I don't know if we want to add a macro that really only serves to create nested tuples. If it created an "anonymous" local struct and had other functionality, it would probably be more useful.
as far as I'm aware a macro would have more uses than just for bundles since the 15 limit is scattered all over since it is the arbitrary number picked to auto-implement tuples traits on tuples. It can be found in system parameters, query components & filters, and I'm sure more I'm forgetting. there has been some work put in to mitigate the problem when it comes to more common arias such as query components (you can make custom WorldQuery impls I think) to make them more readable/usable when large nesting would be needed or the same large groups are used a lot.
personalty I think it would be more useful if we could work out a way to present a custom error message telling people that this is a known limitation and how to fix it. no idea if you can do that with rust/bevy with how it currently is set up;
I think this qualifies as "blocked on variadics": we want to fix this, but increasing the number of all-macros invocations will increase compile times and just move the goal posts.
Can one of the fancy new Rust diagnostics on unimplemented traits help out here? It would be nice to just tell the user "If you have more than 15 things, nest your tuple".