Skip to content

Split Component::register_component_hooks into individual methods #17685

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

Conversation

bushrat011899
Copy link
Contributor

@bushrat011899 bushrat011899 commented Feb 4, 2025

Objective

Solution

  • Deprecated Component::register_component_hooks
  • Added individual methods for each hook which return None if the hook is unused.

Testing

  • CI

Migration Guide

Component::register_component_hooks is now deprecated and will be removed in a future release. When implementing Component manually, also implement the respective hook methods on Component.

// Before
impl Component for Foo {
    // snip
    fn register_component_hooks(hooks: &mut ComponentHooks) {
            hooks.on_add(foo_on_add);
    }
}

// After
impl Component for Foo {
    // snip
    fn on_add() -> Option<ComponentHook> {
            Some(foo_on_add)
    }
}

Notes

I've chosen to deprecate Component::register_component_hooks rather than outright remove it to ease the migration guide. While it is in a state of deprecation, it must be used by Components::register_component_internal to ensure users who haven't migrated to the new hook definition scheme aren't left behind. For users of the new scheme, a default implementation of Component::register_component_hooks is provided which forwards the new individual hook implementations.

Personally, I think this is a cleaner API to work with, and would allow the documentation for hooks to exist on the respective Component methods (e.g., documentation for OnAdd can exist on Component::on_add). Ideally, Component::on_add would be the hook itself rather than a getter for the hook, but it is the only way to early-out for a no-op hook, which is important for performance.

Migration Guide

Component::register_component_hooks has been deprecated. If you are manually implementing the Component trait and registering hooks there, use the individual methods such as on_add instead for increased clarity.

- Deprecated `Component::register_component_hooks`
- Added individual methods for each hook which return `None` if the hook is unused.
@bushrat011899 bushrat011899 added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 4, 2025
@james-j-obrien
Copy link
Contributor

Needs minor doc changes to pass CI, but I like this API and think the changes generally look good.

Copy link
Contributor

@ElliottjPierce ElliottjPierce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Definitely need another opinion on the proc macro code. I'm no expert there.

Only downside here is that it may add more complexity to add more kinds of hooks, but I don't see that happening very often, and I think it's worth it for the readability. IDK why it wasn't designed like this in the first place.


if relationship.is_some() {
if on_insert.is_some() {
let on_add_path = attrs.on_add.map(|path| path.to_token_stream());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IDK, but could you do Path::to_token_stream here instead of passing a closure? I'm no expert here, but if that's possible, it might make it a bit more readable. There's a few other places here too that could use that if it's possible.

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 5, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Feb 5, 2025
Merged via the queue into bevyengine:main with commit d0c0bad Feb 5, 2025
30 checks passed
mrchantey pushed a commit to mrchantey/bevy that referenced this pull request Feb 17, 2025
…evyengine#17685)

# Objective

- Fixes bevyengine#17411

## Solution

- Deprecated `Component::register_component_hooks`
- Added individual methods for each hook which return `None` if the hook
is unused.

## Testing

- CI

---

## Migration Guide

`Component::register_component_hooks` is now deprecated and will be
removed in a future release. When implementing `Component` manually,
also implement the respective hook methods on `Component`.

```rust
// Before
impl Component for Foo {
    // snip
    fn register_component_hooks(hooks: &mut ComponentHooks) {
            hooks.on_add(foo_on_add);
    }
}

// After
impl Component for Foo {
    // snip
    fn on_add() -> Option<ComponentHook> {
            Some(foo_on_add)
    }
}
```

## Notes

I've chosen to deprecate `Component::register_component_hooks` rather
than outright remove it to ease the migration guide. While it is in a
state of deprecation, it must be used by
`Components::register_component_internal` to ensure users who haven't
migrated to the new hook definition scheme aren't left behind. For users
of the new scheme, a default implementation of
`Component::register_component_hooks` is provided which forwards the new
individual hook implementations.

Personally, I think this is a cleaner API to work with, and would allow
the documentation for hooks to exist on the respective `Component`
methods (e.g., documentation for `OnAdd` can exist on
`Component::on_add`). Ideally, `Component::on_add` would be the hook
itself rather than a getter for the hook, but it is the only way to
early-out for a no-op hook, which is important for performance.

## Migration Guide

`Component::register_component_hooks` has been deprecated. If you are
manually implementing the `Component` trait and registering hooks there,
use the individual methods such as `on_add` instead for increased
clarity.
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 targeted quality-of-life change that makes Bevy easier to use D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide 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.

Refactor Component::init_component_hooks to split apart component hook methods
4 participants