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

[Merged by Bors] - Added example of creating a system from a closure #4327

Closed
wants to merge 10 commits into from
Closed

Conversation

bytemuck
Copy link
Contributor

Fixes #4262

@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Mar 25, 2022
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Examples An addition or correction to our examples and removed S-Needs-Triage This issue needs to be labelled labels Mar 25, 2022
examples/README.md Outdated Show resolved Hide resolved
@alice-i-cecile
Copy link
Member

Title suggestion for you @bytemuck (they show up in our commit history, so it's not just bikeshedding): "Added example of creating a system from a closure"

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

Cool! Overall, I think this could use a bit more explanation about what's going on: for a lot of readers, this will be their first introduction to closures at all.

I would also like to see a non-capturing closure demonstrated too, just to show that you don't have to use a Local.

@bytemuck bytemuck changed the title Added Closure Example Added example of creating a system from a closure Mar 25, 2022
@bytemuck
Copy link
Contributor Author

Awesome! I'll take a look for this tomorrow. I gotta sleep, I have school tomorrow. 👍

@bytemuck bytemuck requested a review from alice-i-cecile March 25, 2022 19:00
Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

Much clearer!

@alice-i-cecile
Copy link
Member

@bevyengine/docs-team can I get a second review here?

App::new()
.add_plugin(LogPlugin)
// we can use a non-capturing closure as a system
.add_startup_system(non_capturing_closure)
Copy link
Member

Choose a reason for hiding this comment

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

why did you use startup systems?

Copy link
Contributor Author

@bytemuck bytemuck Apr 4, 2022

Choose a reason for hiding this comment

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

I used a startup system because I wanted it to be called only once.

Copy link
Member

Choose a reason for hiding this comment

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

as you didn't add a scheduler, the app will only run once anyway 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, that's good to know!

};

// create a capturing closure, with a Local value.
let capturing_closure = |value: String| {
Copy link
Member

Choose a reason for hiding this comment

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

this is confusing as this is not a capturing closure

Copy link
Contributor Author

@bytemuck bytemuck Apr 4, 2022

Choose a reason for hiding this comment

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

I think I miss understood what's a capturing closure, I'll reread about them and change that when I come back after school.

Comment on lines 30 to 31
.add_startup_system(move |mut arg: Local<String>| {
*arg = outside_variable.clone();
Copy link
Member

Choose a reason for hiding this comment

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

why use local to demonstrate capturing? the point of capturing is to not need a local at all

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. I don't know why I did that, I'll review my entire PR and recommit when I get home. I think I tried to demonstrate Local and capturing at the same time, and it is just confusing at the end.

outside_variable
);
// you can use outside_variable, or any other variables inside this closure.
// there states will be saved.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// there states will be saved.

a) typo "their", not "there" b) I don't think this line adds much :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are probably right about this. I'll remove it tomorrow 🙂.

Copy link
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

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

I agree with alice comment other than that I had no idea this was even possible so that's good to know.

Comment on lines 9 to 18
// create a closure, with a Local value to be initialized.
let complex_closure = |value: String| {
move |mut arg: Local<String>| {
*arg = value.clone();
info!("Hello from a complex closure! {:?}", arg);

// 'arg' will be saved between calls.
// you could also use an outside variable like presented in then inlined closures
}
};
Copy link
Member

Choose a reason for hiding this comment

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

This is probably not working the way you want it to. Having a Local in a capturing closure is useless. Here you're cloning value to the local at every system execution, so whatever value would the local have would always be replaced by a fresh clone from value. arg would indeed be saved between calls, but the value wouldn't actually be available to the next call.

Instead you can directly use value. The outside closure put it in current scope as mutable, the inner closure capture it and actually modify it as every system execution.

Suggested change
// create a closure, with a Local value to be initialized.
let complex_closure = |value: String| {
move |mut arg: Local<String>| {
*arg = value.clone();
info!("Hello from a complex closure! {:?}", arg);
// 'arg' will be saved between calls.
// you could also use an outside variable like presented in then inlined closures
}
};
let complex_closure = |mut value: String| {
move || {
info!("Hello from a complex closure! {:?}", value);
value = format!("{}o", value);
}
};

This could probably use more comments to explain what's happening...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With some explanation, It makes sense. I should have tested this more aggressively. oops

@mockersf mockersf added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Apr 27, 2022
@jondo2010
Copy link

Wouldn't it be much more useful if you showed receiving a resource or entity query?

@alice-i-cecile
Copy link
Member

Wouldn't it be much more useful if you showed receiving a resource or entity query?

Without the ability to add systems dynamically, this isn't exactly feasible. None of the world's data exists at the time of system initialization. However, once #279 is solved, we should update this example to include that :)

@alice-i-cecile
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Apr 27, 2022
@bytemuck
Copy link
Contributor Author

Wouldn't it be much more useful if you showed receiving a resource or entity query?

Maybe it would be more useful, but I think we should use simplicity over utility in this context, because usually, users will already have knowledge about how the engine works. It will most like not be the first example they will read.

@bors bors bot changed the title Added example of creating a system from a closure [Merged by Bors] - Added example of creating a system from a closure Apr 27, 2022
@bors bors bot closed this Apr 27, 2022
@mockersf
Copy link
Member

Without the ability to add systems dynamically, this isn't exactly feasible. None of the world's data exists at the time of system initialization. However, once #279 is solved, we should update this example to include that :)

it should already work, you can use as a system: |query: Query<(Entity, &Transform)>| {... whatever}

@alice-i-cecile
Copy link
Member

Ah; I'd interpreted the request as "capture data from a resource, and then generate a new system that stores that data". But your read is much more reasonable.

exjam pushed a commit to exjam/bevy that referenced this pull request May 22, 2022
@bytemuck bytemuck deleted the closure branch June 24, 2022 14:53
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
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-Examples An addition or correction to our examples 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.

Add a system closure example
6 participants