-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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] - Add a clear() method to the EventReader that consumes the iterator #4693
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good
We should link to any
from is_empty
. I'd say the docs for is_empty
seem a bit backwarrds too, since e.any()===!e.is_empty()
, but they both have the same docs.
I'm not sure I like how hazardous this is, but this makes it better
Yeah, that's why I would like a better name, but I couldn't find anything. Or at least, anything that isn't overly verbose.
I added a bit more docs to clarify the differences |
It's hard to find a non verbose name since we want to get two outcomes from the function:
As there is no word that encompasses those two actions, I'm OK with making the function name verbose. |
I'm not entirely satisfied with this name, but perhaps something like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, any
doesn't give the idea of what the function does.
I think we can do of the following things:
- keep using
.iter().last().is_some()
as it is the most idiomatic method and is quite understandable, especially if one knows thatlast
consumes the iterator. - renaming
any
to something else, likeconsume_and_report
, which is not 100% clear, but it's something that can be searched up and invites the user to read the docs, whileany
is obscure and completely undiscoverable.
It seems difficult to convey the semantics of system_a should be easy to read, and familiar with anyone that has used a fn system_a(mut events: EventReader<Event>) {
if !events.is_empty() {
events.clear();
// Do the thing!
}
} system_b might be easy to read if you're familiar with this pattern and it saves one line, but is not any less verbose than system_a. fn system_b(mut events: EventReader<Event>) {
if events.iter().last().is_some() {
// Do the thing!
}
} |
I really like @devil-ira's suggestion here. I like that it's so much more explicit, and the boilerplate isn't too bad. |
Should That is, recognise that it's a logic error to not clear it? Note that people could still use |
Hmm. I like this idea: it's a good additional layer of safety, and I agree with you that this is almost always a logic error. That said, I'm nervous about the mechanism: the addition of panics in edge cases is not fun. What about a debug assert on drop? |
I wonder if we could also change the breakout example to use the new approach. |
c7545e6
to
70a7467
Compare
I decided to use @devil-ira suggestion of using a clear method with no returns. It's a bit verbose but it makes the pattern a lot clearer. I also used it in the breakout example as @Nilirad suggested. I also added a simple test. Is it possible to reset the reviews? I wouldn't consider them valid after this change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this approach much better.
IMO this is ready to merge once:
- Nits are addressed.
- A doc example is added.
- PR title and description are updated.
The API doc example can be easily added by copying it from the test. |
Should I just use the test directly in the doc example and remove the test? |
I would prefer the example being under a level 2 “Example” header. The example code should also be inside a common system function and boilerplate lines (arguably everything except the system function) should be hidden with |
Can we have clear return true if there was anything to clear? I've been doing something similar: if level_unloaded.iter().count() > 0 {
**selected_piece = None;
} It might be a little weird, but it's not too different from if level_unloaded.clear() {
**selected_piece = None;
} |
Co-authored-by: Federico Rinaldi <[email protected]>
92907db
to
f399c4a
Compare
bors r+ |
…4693) # Objective - It's pretty common to want to check if an EventReader has received one or multiple events while also needing to consume the iterator to "clear" the EventReader. - The current approach is to do something like `events.iter().count() > 0` or `events.iter().last().is_some()`. It's not immediately obvious that the purpose of that is to consume the events and check if there were any events. My solution doesn't really solve that part, but it encapsulates the pattern. ## Solution - Add a `.clear()` method that consumes the iterator. - It takes the EventReader by value to make sure it isn't used again after it has been called. --- ## Migration Guide Not a breaking change, but if you ever found yourself in a situation where you needed to consume the EventReader and check if there was any events you can now use ```rust fn system(events: EventReader<MyEvent>) { if !events.is_empty { events.clear(); // Process the fact that one or more event was received } } ``` Co-authored-by: Charles <[email protected]>
Build failed: |
bors retry |
…4693) # Objective - It's pretty common to want to check if an EventReader has received one or multiple events while also needing to consume the iterator to "clear" the EventReader. - The current approach is to do something like `events.iter().count() > 0` or `events.iter().last().is_some()`. It's not immediately obvious that the purpose of that is to consume the events and check if there were any events. My solution doesn't really solve that part, but it encapsulates the pattern. ## Solution - Add a `.clear()` method that consumes the iterator. - It takes the EventReader by value to make sure it isn't used again after it has been called. --- ## Migration Guide Not a breaking change, but if you ever found yourself in a situation where you needed to consume the EventReader and check if there was any events you can now use ```rust fn system(events: EventReader<MyEvent>) { if !events.is_empty { events.clear(); // Process the fact that one or more event was received } } ``` Co-authored-by: Charles <[email protected]>
…evyengine#4693) # Objective - It's pretty common to want to check if an EventReader has received one or multiple events while also needing to consume the iterator to "clear" the EventReader. - The current approach is to do something like `events.iter().count() > 0` or `events.iter().last().is_some()`. It's not immediately obvious that the purpose of that is to consume the events and check if there were any events. My solution doesn't really solve that part, but it encapsulates the pattern. ## Solution - Add a `.clear()` method that consumes the iterator. - It takes the EventReader by value to make sure it isn't used again after it has been called. --- ## Migration Guide Not a breaking change, but if you ever found yourself in a situation where you needed to consume the EventReader and check if there was any events you can now use ```rust fn system(events: EventReader<MyEvent>) { if !events.is_empty { events.clear(); // Process the fact that one or more event was received } } ``` Co-authored-by: Charles <[email protected]>
…evyengine#4693) # Objective - It's pretty common to want to check if an EventReader has received one or multiple events while also needing to consume the iterator to "clear" the EventReader. - The current approach is to do something like `events.iter().count() > 0` or `events.iter().last().is_some()`. It's not immediately obvious that the purpose of that is to consume the events and check if there were any events. My solution doesn't really solve that part, but it encapsulates the pattern. ## Solution - Add a `.clear()` method that consumes the iterator. - It takes the EventReader by value to make sure it isn't used again after it has been called. --- ## Migration Guide Not a breaking change, but if you ever found yourself in a situation where you needed to consume the EventReader and check if there was any events you can now use ```rust fn system(events: EventReader<MyEvent>) { if !events.is_empty { events.clear(); // Process the fact that one or more event was received } } ``` Co-authored-by: Charles <[email protected]>
…evyengine#4693) # Objective - It's pretty common to want to check if an EventReader has received one or multiple events while also needing to consume the iterator to "clear" the EventReader. - The current approach is to do something like `events.iter().count() > 0` or `events.iter().last().is_some()`. It's not immediately obvious that the purpose of that is to consume the events and check if there were any events. My solution doesn't really solve that part, but it encapsulates the pattern. ## Solution - Add a `.clear()` method that consumes the iterator. - It takes the EventReader by value to make sure it isn't used again after it has been called. --- ## Migration Guide Not a breaking change, but if you ever found yourself in a situation where you needed to consume the EventReader and check if there was any events you can now use ```rust fn system(events: EventReader<MyEvent>) { if !events.is_empty { events.clear(); // Process the fact that one or more event was received } } ``` Co-authored-by: Charles <[email protected]>
Objective
events.iter().count() > 0
orevents.iter().last().is_some()
. It's not immediately obvious that the purpose of that is to consume the events and check if there were any events. My solution doesn't really solve that part, but it encapsulates the pattern.Solution
.clear()
method that consumes the iterator.Migration Guide
Not a breaking change, but if you ever found yourself in a situation where you needed to consume the EventReader and check if there was any events you can now use