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

Fix required components documentation ambiguity #16539

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ use derive_more::derive::{Display, Error};
///
/// In general, this shouldn't happen often, but when it does the algorithm is simple and predictable:
/// 1. Use all of the constructors (including default constructors) directly defined in the spawned component's require list
/// 2. In the order the requires are defined in `#[require()]`, recursively visit the require list of each of the components in the list (this is a Depth First Search). When a constructor is found, it will only be used if one has not already been found.
/// 2. In the order the requires are defined in `#[require()]`, recursively visit the require list of each of the components in the list (this is a Breadth First Search). When a constructor is found, it will only be used if one has not already been found.
Copy link
Member

@alice-i-cecile alice-i-cecile Nov 28, 2024

Choose a reason for hiding this comment

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

Suggested change
/// 2. In the order the requires are defined in `#[require()]`, recursively visit the require list of each of the components in the list (this is a Breadth First Search). When a constructor is found, it will only be used if one has not already been found.
/// 2. In the order the requires are defined in `#[require()]`, recursively visit the require list of each of the components in the list. When a constructor is found, it will only be used if one has not already been found.
///
/// This is a Depth First Search, but constructors of a direct requires are evaluated before recursing.

Copy link
Contributor

Choose a reason for hiding this comment

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

That sounds a bit off. Maybe:

/// The algorithm for choosing the constructor from the tree:
/// 1. A constructor from a direct #[requires()], if one exists, is selected with priority.
/// 2. Otherwise, perform a Depth First Search on the tree of requirements and select the first one found.

Copy link
Contributor

@benfrankel benfrankel Nov 28, 2024

Choose a reason for hiding this comment

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

I think the main issue with the current wording is that step 1 refers to the "spawned component", which seems to suggest that the step only applies to the component you directly spawn (aka the root of the tree), when it actually applies to every component visited during the DFS. I'd reword it to something roughly like this:

  1. Starting with the spawned component, recusively visit the require list of each of the components in the list, in the order the requires are defined in #[require()] (this is a Depth First Search).
  2. Whenever a component is visited, use all of the constructors (including default constructors) directly defined in its require list, except for the components whose constructors have already been found.

@BenjaminBrienen's wording is good.

Copy link
Author

Choose a reason for hiding this comment

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

On my readthrough of it I thought "depth-first" was somewhat misleading, but maybe I'm just misunderstanding the term.

Copy link
Contributor

Choose a reason for hiding this comment

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

The implementation is actually a depth-first search, it just collects the constructors whenever it visits a component.

///
/// From a user perspective, just think about this as the following:
/// 1. Specifying a required component constructor for Foo directly on a spawned component Bar will result in that constructor being used (and overriding existing constructors lower in the inheritance tree). This is the classic "inheritance override" behavior people expect.
Expand Down