-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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 std::iter::from_fn #55977
Comments
Some thoughts: At least Haskell, Java, Scala, and itertools call the
|
That is in my opinion just not the same function. (And it’s a less useful one.)
Yes, this is the point: bridging closures to iterators in (almost, if explicit state is kept) the simplest possible way.
This is a really convoluted work-around. I’d write a custom iterator type before coming up with it. And it requires a "sentinel" value that indicates end of iteration. If the iterated type doesn’t have such an unused value available, you’d have to make an infinite iterator of Option, then use takeWhile, then use map to unwrap those options. |
@jdahlstrom there's already repeat_with for infinite iterators. |
If we pick |
This API is not about repetition any more than any iterator is intended to be used by repeatedly calling |
We discussed this awhile back in a libs triage meeting and I've been meaning to post an update here as well! It was sort of up in the air about an explicit state vs implicit-state-via-closure parameter. I know I still personally feel that this probably doesn't need an explicit state parameter on In terms of naming it was pointed out that this is similar in functionality to In any case, just some thoughts! |
How about removing the explicit state and renaming to let mut count = 0;
let counter = std::iter::from_fn(move || {
count += 1;
if count < 6 {
Some(count)
} else {
None
}
});
assert_eq!(counter.collect::<Vec<_>>(), &[1, 2, 3, 4, 5]); |
@SimonSapin should be |
Ah yes! Fixed, thanks. |
|
I do feel strongly that something called |
@scottmcm I think this is a fair point, which is part of why I’m suggesting to rename :) |
This API is unstable. CC rust-lang#55977 (comment)
PR doing this: #58062 |
Rename iter::unfold to iter::from_fn and remove explicit state This API is unstable. CC #55977 (comment)
Rename iter::unfold to iter::from_fn and remove explicit state This API is unstable. CC #55977 (comment)
With that merged, I think the remaining questions are resolved. Though of course we can still bikeshed the new name. @rfcbot fcp merge |
Team member @SimonSapin has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
My only nitpick with calling this This is a minor nitpick, but it does cause some cognitive dissonance for me and I worry it will do the same for people learning the language. Anybody have any thoughts or opinions on that? |
The name should be mentally read "from |
Indeed, the name is intended to refer to the I’m open to another name though, if there are suggestions. |
Again a nitpick, but technically the bound is So, let me start this (larger than intended) comment by stating that I would be able to live with It's unfortunate we can't use
I like the idea of
|
Naming aside, I think the design with the explicit state was better. In particular, it's ergonomic since a temporary match something {
OtherVariant => { /* ... */ }
SomeVariant => Box::new({
let mut count = 0;
std::iter::from_fn(move || {
count += 1;
if count < 6 {
Some(count)
} else {
None
}
})
}),
}
// vs.
match something {
OtherVariant => { /* ... */ }
SomeVariant => Box::new(std::iter::from_fn(0, |count| {
*count += 1;
if *count < 6 {
Some(*count)
} else {
None
}
})),
} The former encourages right-ward drift while the latter does not. |
The problem is that you'll necessary have both the parameter and the closure, which is confusing. Like, even docs for unfold do not use explicit state. If explicit state is more ergonomic in a particular instance, there's a high chance that match something {
OtherVariant => { /* ... */ }
SomeVariant => Box::new(std::iter::successors(Some(1), |count| {
Some(count + 1).filter(|it| it < 6)
})),
} |
But so does |
Shall the word "unfold" be somewhere in docs for Something like "similar function was previously called |
It’s not quite the same as |
But previous The same or not the same, the function is unfold-esque, so is relevant for searchs for the world "unfold". |
The final comment period, with a disposition to merge, as per the review above, is now complete. |
Stabilize iter::successors and iter::from_fn FCP: rust-lang#58045 (comment), rust-lang#55977 (comment)
Closed by #58576. |
Update: API modified in #58062:
This API is being proposed in #55869:
unfold
was previously in the standard library but was deprecated and then removed in Rust 1.3 for not having “gained enough traction to retain its position in the standard library”. It is now available in theitertools
crate.My personal opinion is that we’ve been very conservative with inclusion in std in the months before and after 1.0 but we’ve slowing been relaxing the criteria, with in increasing number of small convenience functions and methods. Both
unfold
andsuccessors
feel general-purpose and fundamental enough to me to belong in the standard library.Unresolved questions:
Should the state field of
Unfold
be public?Should
unfold
have explicit state for consistency withfold
, or should it be a more trivial bridging of closures to iterators with state kept in the closure’s environment or captures?Update: moved to Moved to #58045:
The text was updated successfully, but these errors were encountered: