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
Tracking issue for ControlFlow
enum, for use with try_fold
and in Try
#75744
Comments
Big +1 for this. A |
As the one who added @NoraCodes Want to take on making a PR here? There's probably a few parts:
Feel free to ping me (here, in a draft PR, on community Discord, or on Zulip) if you have questions. Its methods are probably imperfect right now, but if it's unstable that's ok. People can start using it on nightly as we'll find out what needs fixing before stabilization that way. |
I would be happy to do this. I may ask for some help getting a development environment set up as I have yet to contribute to the core libraries. |
This comment has been minimized.
This comment has been minimized.
LoopState
to make try_fold
closures easier to write and more idiomaticControlFlow
enum, for use with try_fold
and in Try
…=scottmcm Rename and expose LoopState as ControlFlow Basic PR for rust-lang#75744. Addresses everything there except for documentation; lots of examples are probably a good idea.
Congrats on your first core libraries PR, @NoraCodes! Want to take on the generic parameter reordering (that morse brought up in #76204 (comment)) next? |
Thanks @scottmcm! I definitely do want to do that. I'll put in a PR either this weekend or Tuesday.
|
Another example of a type that's pretty close to this: the |
An MCP to use this more often in the compiler: rust-lang/compiler-team#374 Conveniently that also suggests that EDIT: A great comment on the PR that implements the MCP (#78182 (comment)):
Nice to see confirmation of the value 🙂 |
Apologies for taking forever on this. I set up a Rust dev env on my new PC and fixed the nits in that PR so we should be good to go. I'll move forward with the other work, and documentation. |
…, r=scottmcm Add `ControlFlow::is_{break,continue}` methods r? @scottmcm cc rust-lang#75744
Will it be stabilized in 1.55? It's in the stabilized APIs section. |
I wonder if An example how this could be utilized can be found here: https://gist.github.com/Robbepop/756eedb75466e09e0262ef917818c553 |
Would it be possible to also add boolean constructors for impl ControlFlow<(), ()> {
#[must_use]
pub fn continue_if(should_continue: bool) -> Self {
if should_continue {
ControlFlow::CONTINUE
} else {
ControlFlow::BREAK
}
}
#[must_use]
pub fn break_if(should_break: bool) -> Self {
if should_break {
ControlFlow::BREAK
} else {
ControlFlow::CONTINUE
}
}
} As I am refactoring some prior |
@MomoLangenstein For a simple method addition, you can absolutely send a PR. With https://doc.rust-lang.org/std/primitive.bool.html#method.then stable, there's probably space for something in this area. What it should be, I don't know. I'm a bit skeptical of both the |
@MomoLangenstein AFAIK this could be done as an external lib. Actually, I think it can be implemented on stable, as the enum is stabilized. 🤔 |
@dbofmmbt Yes, that's true. Though I think this would really be a convenience function that serves to better document the code functionality more concisely, which would be valuable to have in |
@scottmcm I think the most common pattern would be along the lines of if some_condition {
break;
} meaning that |
trait BoolControlFlowExt {
fn break(self) -> ControlFlow;
fn continue(self) -> ControFlow;
}
impl BoolControlFlowExt for bool {
fn break(self) -> ControlFlow {
match self {
true => ControlFlow::Break,
false => ControlFlow::Continue,
}
fn continue(self) -> ControlFlow {
match self {
true => ControlFlow::Continue,
false => ControlFlow::Break,
}
}
}
// Some code...
....
my_condition.break()?;
.... @MomoLangenstein what do you think? Sorry about the (probably bad) trait name. I would define another trait extension for ControlFlow too, as AFAIK it is not easily convertible between other Try types today, and would be nice to convert between them and use |
@dbofmmbt Thank you very much, that looks great! Personally, when using long boolean conditions, I'd prefer the explicit ControlFlow::break_if(steps >= max_steps || next_event_time >= max_event_time) instead of the more implicit (steps >= max_steps || next_event_time >= max_event_time).break() But yes, both of these could be implemented with an external extension trait (so thanks again for the suggestion). |
Note that if, as above, the common case here is You might consider experimenting with |
I guess I meant the |
Not sure if this is the right place for this discussion but I wonder if fn g() -> std::ops::ControlFlow<u8> {
std::ops::ControlFlow::Break(1)
}
fn f() -> u8 {
g()?; // does not compile in 1.61: E0277 the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
0
}
// f() returns 1. This seems useful in cases where the caller of EDIT: It seems I misunderstood the |
Adding my 2c here - a |
@benluelo Since |
…inators, r=scottmcm Add map_continue and continue_value combinators to ControlFlow As suggested in this comment: rust-lang#75744 (comment) Related tracking issue: rust-lang#75744 r? `@scottmcm`
…inators, r=scottmcm Add map_continue and continue_value combinators to ControlFlow As suggested in this comment: rust-lang#75744 (comment) Related tracking issue: rust-lang#75744 r? ``@scottmcm``
…inators, r=scottmcm Add map_continue and continue_value combinators to ControlFlow As suggested in this comment: rust-lang#75744 (comment) Related tracking issue: rust-lang#75744 r? ```@scottmcm```
…inators, r=scottmcm Add map_continue and continue_value combinators to ControlFlow As suggested in this comment: rust-lang#75744 (comment) Related tracking issue: rust-lang#75744 r? ````@scottmcm````
…inators, r=scottmcm Add map_continue and continue_value combinators to ControlFlow As suggested in this comment: rust-lang#75744 (comment) Related tracking issue: rust-lang#75744 r? `````@scottmcm`````
…inators, r=scottmcm Add map_continue and continue_value combinators to ControlFlow As suggested in this comment: rust-lang#75744 (comment) Related tracking issue: rust-lang#75744 r? ``````@scottmcm``````
…r=scottmcm Add map_continue and continue_value combinators to ControlFlow As suggested in this comment: rust-lang/rust#75744 (comment) Related tracking issue: rust-lang/rust#75744 r? ``````@scottmcm``````
I found a usecase where maybe ControlFlow could be used as well, having an early exit from a In case this should be in a new issue, let me know. Something like impl<T> ControlFlow<T, T> {
pub fn value(self) -> T {
match self {
ControlFlow::Continue(value) | ControlFlow::Break(value) => value,
}
}
} allowing to do let value = smth.try_fold(Vec::new(), |aggr, curr| {
// Do something
if todo!("Some condition that checks weather aggr is ready for early exit e.g. full") {
ControlFlow::Break(aggr)
} else {
ControlFlow::Continue(aggr)
}
}).value(); |
I've been wondering about whether we could move some of the shared operations between I realized that Proposed Method Naming
|
@ModProg I have also run into a case where such a method would be desirable |
The naming of Should the two methods be renamed before stabilization? Proposed Method Naming
|
They cannot have those names because they are strict keywords. |
(edited to turn this into a tracking issue, as it's referenced by the
unstable
attributes)This is a tracking issue for the
std::ops::ControlFlow
type.The feature gate for the issue is
#![feature(control_flow_enum)]
.About tracking issues
Tracking issues are used to record the overall progress of implementation.
They are also uses as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
Result
stry_trait_v2
#84767Iterator::try_fold
andIterator::try_for_each
Unresolved Questions
Should we change the generic parameter order? https://github.com/rust-lang/rust/pull/76204/files#r481357223done in change the order of type arguments on ControlFlow #76614(probably not theRemoved those ones in Demoteinto_try
ones, https://github.com/rust-lang/rust/pull/76204/files#r481515347)ControlFlow::{from|into}_try
topub(crate)
#85645CONTINUE
/BREAK
constants valuable? See StabilizeControlFlow::{BREAK, CONTINUE}
#102697B = ()
too? (Might be nice fortry_for_each
uses.)Implementation history
Initial PR that added
LoopState
as an implementation detail: #45595PR that exposed as unstable and renamed to
ControlFlow
: #76204Added
BREAK
/CONTINUE
associated constants: #76318Changed type parameter order and defaulted
C = ()
: #76614Add
is_break
andis_continue
methods: #78200I work with an organization that has a large amount of Rust graph traversal code as part of its core business. We used to use
itertools
'sfold_while
for short-circuiting functional-style loops over slices of our graphs, which is now deprecated in favor oftry_fold
.try_fold
is great, but the lack of a standard library providedTry
implementation that makes the loop semantics clear is confusing. We created our own, which is fine, but I think it would make a lot of sense to exposeLoopState
and provide an example in the docs.Originally related to: rust-itertools/itertools#469
The text was updated successfully, but these errors were encountered: