Skip to content

Question regarding mutability of Query::iter_mut() #1301

@Bromeon

Description

@Bromeon

Hello everyone!
On https://bevyengine.org/news/bevy-0-4/, there's this code snippet:

// on each update this system runs once and internally iterates over each entity
fn system(time: Res<Time>, query: Query<(Entity, &mut Transform)>) {
    for (entity, mut transform) in query.iter_mut() {
        // do per-entity logic here
    }
}

Since iter_mut() takes &mut self, the function parameter should be mut query, no?


Given that, I'll try to fill out the feature template, although it's more of a general API discussion than a concrete request 🙂

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

For me, it's not immediately obvious that Query::iter_mut() operates on &mut self, as logically, the query itself is not mutated, but rather the components being queried.
Also, iter() already provides a specific trait bound ReadOnlyFetch, so it cannot be used for mutable queries:

/// Iterates over the query results. This can only be called for read-only queries
#[inline]
pub fn iter(&self) -> QueryIter<'_, Q, F>
    where
        Q::Fetch: ReadOnlyFetch, // <-- this bound
{
    // SAFE: system runs without conflicts with other systems.
    // same-system queries have runtime borrow checks when they conflict
    unsafe { self.world.query_unchecked() }
}

/// Iterates over the query results
#[inline]
pub fn iter_mut(&mut self) -> QueryIter<'_, Q, F> {
    // SAFE: system runs without conflicts with other systems.
    // same-system queries have runtime borrow checks when they conflict
    unsafe { self.world.query_unchecked() }
}

Is the actual reason to enforce unique access (non-aliasing), so that no two mutable queries can run at the same time? The only thing I can imagine here is doing that in a nested loop, and doing so would probably not make sense for iter() queries either.

What solution would you like?

If compatible with safety, allowing iter_mut() on &self could be considered.
If not, we can document the background why &mut self is used.

What alternative(s) have you considered?

Leaving everything as is, fixing the 0.4 release notes and improving documentation.

Additional context

I looked at #753 (aligning with Rust conventions) and #796 (a bug related to safety, although not directly related to this).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and events

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions