Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - implemented #[bundle(ignore)] #6123

Closed
wants to merge 9 commits into from

Conversation

maccesch
Copy link
Contributor

Objective

Fixes #5559

Replaces #5628

Solution

Because the generated method from_components() creates an instance of Self my implementation requires any field type that is marked to be ignored to implement Default.


Changelog

Added the possibility to ignore fields in a bundle with #[bundle(ignore)]. Typically used when PhantomData needs to be added to a Bundle.

@maccesch maccesch changed the title implemented #[bundle(ignore)] WIP: implemented #[bundle(ignore)] Sep 29, 2022
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Usability A simple quality-of-life change that makes Bevy easier to use labels Sep 29, 2022
@alice-i-cecile
Copy link
Member

FYI Github has a built-in "Draft mode" for WIP PRs :)

@maccesch maccesch changed the title WIP: implemented #[bundle(ignore)] implemented #[bundle(ignore)] Sep 30, 2022
@maccesch
Copy link
Contributor Author

@alice-i-cecile Ok all fixed

crates/bevy_ecs/macros/src/lib.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/macros/src/lib.rs Show resolved Hide resolved
crates/bevy_ecs/macros/src/lib.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/macros/src/lib.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/macros/src/lib.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/macros/src/lib.rs Outdated Show resolved Hide resolved
maccesch and others added 6 commits September 30, 2022 11:39
Co-authored-by: Nathan Ward <43621845+NathanSWard@users.noreply.github.com>
Co-authored-by: Nathan Ward <43621845+NathanSWard@users.noreply.github.com>
Co-authored-by: Afonso Lage <lage.afonso@gmail.com>
Co-authored-by: Afonso Lage <lage.afonso@gmail.com>
@maccesch
Copy link
Contributor Author

@alice-i-cecile I was thinking about this, and I'm not sure about what I'm about to propose 😄

Instead of having a #[bundle(ignore)] should we just ignore PhantomData by default? Making it less redundant...

The downside would be that if you had a custom type called PhantomData you couldn't use it with bundles. But to me that feels like a very small price to pay.

@NathanSWard
Copy link
Contributor

NathanSWard commented Sep 30, 2022

@alice-i-cecile I was thinking about this, and I'm not sure about what I'm about to propose 😄

Instead of having a #[bundle(ignore)] should we just ignore PhantomData by default? Making it less redundant...

The downside would be that if you had a custom type called PhantomData you couldn't use it with bundles. But to me that feels like a very small price to pay.

Don't actually think this is possible, at least at the macro level using the name PhantomData.
Since it's very easy someone could do something like:

type GhostData<T> = PhantomData<T>;

#[derive(Bundle)]
pub struct MyBundle<T> {
  ghost: GhostData<T>,
  // ..
}

And it's also impossible to do it via any sort of type matching e.g.

if TypeId::of<BundleField>() == TypeId::of<PhantomData<?>> {}

Since PhantomData is generic over T where T could be any type.

Granted I'm sure there's probably some hackery you could do with a trait, however, IMO #[bundle(ignore)] is by far the cleanest solution.
Not only that, it's possible there are other use cases to ignore a type inside a bundle. Granted PhantomData is probably like 90% of use cases.

@NathanSWard
Copy link
Contributor

Oh, and one last thing, could we add a test for this?
Basically just have some bundle where we #[bundle(ignore)] one of the fields, and ensure that when we insert the bundle for an entity, the ignored component does not exist for that entity.

@maccesch
Copy link
Contributor Author

maccesch commented Sep 30, 2022

@NathanSWard When making my suggestion I actually had these limitations in mind. I implemented a derive macro for Dioxus where we decided to make all Option<...> types optional by default (just matching by name) because even though you can do all of these shenanigans you demonstrated almost nobody will. So the gain in ergonomics was prioritized over these unlikely edge cases.

Having said that it is true that the aforementioned Option default is something that is used all the time in contrast to this PhantomData case which is probably not used that frequently.

I still think the ergonomics would be worth it. Maybe instead we could have a

#[bundle(include)]
data: PhantomData<...>,

that counteracts the default exclusion for the case that somebody really did name a component "PhantomData" (lol) and leave the #[bundle(ignore)] for those cases where somebody indeed made a type alias for PhantomData.

So in conclusion:

  • PhantomData is ignored by default
  • can be counteracted by #[bundle(include)]
  • you can manually force sth to be excluded by #[bundle(ignore)]

@NathanSWard
Copy link
Contributor

Fwiw, I'm definitely not a big fan of #[bundle(include)].
And forcing people to explicitly use the words PhantomData in their bundle's member feels like more of an anti-pattern and more of a possible future headache then just requiring people to use #[bundle(ignore)].

I'm just generally against any sort of "stringly" typed imementation which is what you seem to be proposing.

@NathanSWard
Copy link
Contributor

NathanSWard commented Sep 30, 2022

This also extends to other marker types, e.g. PhantomPinned. Having a simple #[bundle(ignore)] to account for any marker like type seems like the most generic/simplest solution, instead of just special casing for PhantomData where the implementation has sharp corner cases.

@alice-i-cecile
Copy link
Member

This also extends to other marker types, e.g. PhantomPinned. Having a simple #[bundle(ignore)] to account for any marker like type seems like the most generic/simplest solution, instead of just special casing for PhantomData where the implementation has sharp corner cases.

Yep, this is my feeling. I also like how much more explicit the ignore solution is. Deviations from the expected behavior should be called out.

@maccesch
Copy link
Contributor Author

maccesch commented Oct 1, 2022

Ok got it. Thanks for considering 😄

@maccesch
Copy link
Contributor Author

maccesch commented Oct 1, 2022

@NathanSWard test added ✔️

@SpecificProtagonist
Copy link
Contributor

I agree that we should have #[bundle(ignore)], but does it make sense to unsafe impl<T: Sync + Send + 'static> Bundle for PhantomData<T> (as a no-op) so derive(Bundle) just works, similarly how empty tuples implement Bundle?

@maccesch maccesch requested review from afonsolage and NathanSWard and removed request for NathanSWard and afonsolage October 2, 2022 00:36
@alice-i-cecile
Copy link
Member

I agree that we should have #[bundle(ignore)], but does it make sense to unsafe impl<T: Sync + Send + 'static> Bundle for PhantomData (as a no-op) so derive(Bundle) just works, similarly how empty tuples implement Bundle?

IMO this is too implicit. It leads to weird behavior where you can e.g. insert a PhantomData<T> and it does nothing silently.

@maccesch maccesch requested review from afonsolage and removed request for NathanSWard October 9, 2022 19:57
@BoxyUwU
Copy link
Member

BoxyUwU commented Oct 17, 2022

derive(WorldQuery) and derive(SystemParam) both use #[world_query(ignore)] [system_param(ignore)] instead of trying to be clever about implicitly ignoring PhantomData. Regardless of whether this is a good/bad idea, all 3 derives should be consistent and imo this is definitely not the PR to be implementing Bundle/SystemParam/WorldQuery for PhantomData (or trying to match the struct name in the proc macro).

@BoxyUwU BoxyUwU added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Oct 17, 2022
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.

Great macro code, good tests, useful little feature.

bors r+

bors bot pushed a commit that referenced this pull request Oct 24, 2022
# Objective

Fixes #5559

Replaces #5628

## Solution

Because the generated method from_components() creates an instance of Self my implementation requires any field type that is marked to be ignored to implement Default.

---

## Changelog

Added the possibility to ignore fields in a bundle with `#[bundle(ignore)]`. Typically used when `PhantomData` needs to be added to a `Bundle`.
@bors
Copy link
Contributor

bors bot commented Oct 24, 2022

Build failed (retrying...):

bors bot pushed a commit that referenced this pull request Oct 24, 2022
# Objective

Fixes #5559

Replaces #5628

## Solution

Because the generated method from_components() creates an instance of Self my implementation requires any field type that is marked to be ignored to implement Default.

---

## Changelog

Added the possibility to ignore fields in a bundle with `#[bundle(ignore)]`. Typically used when `PhantomData` needs to be added to a `Bundle`.
@bors bors bot changed the title implemented #[bundle(ignore)] [Merged by Bors] - implemented #[bundle(ignore)] Oct 24, 2022
@bors bors bot closed this Oct 24, 2022
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 28, 2022
# Objective

Fixes bevyengine#5559

Replaces bevyengine#5628

## Solution

Because the generated method from_components() creates an instance of Self my implementation requires any field type that is marked to be ignored to implement Default.

---

## Changelog

Added the possibility to ignore fields in a bundle with `#[bundle(ignore)]`. Typically used when `PhantomData` needs to be added to a `Bundle`.
Pietrek14 pushed a commit to Pietrek14/bevy that referenced this pull request Dec 17, 2022
# Objective

Fixes bevyengine#5559

Replaces bevyengine#5628

## Solution

Because the generated method from_components() creates an instance of Self my implementation requires any field type that is marked to be ignored to implement Default.

---

## Changelog

Added the possibility to ignore fields in a bundle with `#[bundle(ignore)]`. Typically used when `PhantomData` needs to be added to a `Bundle`.
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective

Fixes bevyengine#5559

Replaces bevyengine#5628

## Solution

Because the generated method from_components() creates an instance of Self my implementation requires any field type that is marked to be ignored to implement Default.

---

## Changelog

Added the possibility to ignore fields in a bundle with `#[bundle(ignore)]`. Typically used when `PhantomData` needs to be added to a `Bundle`.
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 simple quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add ability to ignore field of bundle
6 participants