-
Notifications
You must be signed in to change notification settings - Fork 66
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
Reflexive world queries #68
base: main
Are you sure you want to change the base?
Conversation
I'd welcome an improvement to this honestly. /// Query for figuring out if a given animal is [`Piglet`], [`Juvenile`] or [`Adult`].
/// See [`AgeGroup`].
#[derive(Debug, WorldQuery)]
pub struct ReadAgeGroup {
piglet: Option<&'static Piglet>,
juvenile: Option<&'static Juvenile>,
adult: Option<&'static Adult>,
//FIXME: this should probably have `With<WildBoar>` on it.
}
impl ReadAgeGroupItem<'_> {
/// Returns the [`AgeGroup`] of the given entity.
pub fn get(&self) -> AgeGroup {
match (self.piglet, self.juvenile, self.adult) {
// piglet
(Some(_), None, None) => AgeGroup::Piglet,
// juvenile
(None, Some(_), None) => AgeGroup::Juvenile,
// adult
(None, None, Some(_)) => AgeGroup::Adult,
_ => panic!("`WildBoar`-entity has the wrong age-groups component."),
}
}
} Notice the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well-motivated and a good change. I'm in favor!
This is particularly nasty when trying to write impl blocks for the QueryItem type. It's a great pattern, but hard to discover and hard to document.
Co-authored-by: Alice Cecile <[email protected]>
## Drawbacks | ||
|
||
This will add slightly more friction in some cases, since | ||
types such as `&mut T` are forbidden from being used in the derive macro. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is my biggest gripe with this approach. This sacrifices the simpler mental model for normal users and happy path and forces any mutative query to use Mut<T>
over &mut T
, and that mapping from &T
to &mut T
is now lost.
We can address this by implementing &mut T: World Query
, and just forcibly mark everything matched as mutated, but that would make the distinction between &mut T
and Mut<T>
extremely nuanced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm nervous about that, especially because of how subtly it breaks existing code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is my biggest gripe with this approach. This sacrifices the simpler mental model for normal users and happy path and forces any mutative query to use
Mut<T>
over&mut T
, and that mapping from&T
to&mut T
is now lost.
Not sure if we're on the same page, but I want to clarify that you can still write Query<&mut T>
and have it return Mut<T>
-- the reflexive constraint is only for named WorldQuery
structs made using the derive macro. Very little user code will be affected in practice. I think this constraint will surprise users at first, but I also think it will make sense when they think about it, or read the docs and have it explained to them (we'll have to think of a good way of explaining this that would make it click more easily). Also, this behavior is consistent with how the SystemParam
derive macro works, which might make it easier to understand for some users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another point I want to add: using &mut T
in a derived WorldQuery already fails with a confusing type error, until you read the docs and see that you need the special attribute #[world_query(mutable)]
. Since we're already relying on the user to read the docs for this macro to be usable, I don't think there's much of a regression caused by requiring world queries to be reflexive.
RENDERED.
Currently, the
#[derive(WorldQuery)]
macro produces types with a sub-par API. For each user-defined type, the macro generates an additional "Item" type associated with it, and the API is spread between these two types in a way that increases complexity and makes custom world query types more difficult to use and create. I propose we amend this by requiring derived world queries to be reflexive, which removes the need for "Item" types.