# Objective
- Make working with immutable components more ergonomic
- Assist #16662
## Solution
Added `modify_component` to `World` and `EntityWorldMut`. This method
"removes" a component from an entity, gives a mutable reference to it to
a provided closure, and then "re-inserts" the component back onto the
entity. This replacement triggers the `OnReplace` and `OnInsert` hooks,
but does _not_ cause an archetype move, as the removal is purely
simulated.
## Testing
- Added doc-tests and a unit test.
---
## Showcase
```rust
use bevy_ecs::prelude::*;
/// An immutable component.
#[derive(Component, PartialEq, Eq, Debug)]
#[component(immutable)]
struct Foo(bool);
let mut world = World::default();
let mut entity = world.spawn(Foo(false));
assert_eq!(entity.get::<Foo>(), Some(&Foo(false)));
// Before the closure is executed, the `OnReplace` hooks/observers are triggered
entity.modify_component(|foo: &mut Foo| {
foo.0 = true;
});
// After the closure is executed, `OnInsert` hooks/observers are triggered
assert_eq!(entity.get::<Foo>(), Some(&Foo(true)));
```
## Notes
- If the component is not available on the entity, the closure and hooks
aren't executed, and `None` is returned. I chose this as an alternative
to returning an error or panicking, but I'm open to changing that based
on feedback.
- This relies on `unsafe`, in particular for accessing the `Archetype`
to trigger hooks. All the unsafe operations are contained within
`DeferredWorld::modify_component`, and I would appreciate that this
function is given special attention to ensure soundness.
- The `OnAdd` hook can never be triggered by this method, since the
component must already be inserted. I have chosen to not trigger
`OnRemove`, as I believe it makes sense that this method is purely a
replacement operation, not an actual removal/insertion.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Malek <50841145+MalekiRe@users.noreply.github.com>