-
Notifications
You must be signed in to change notification settings - Fork 341
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
add stream::from_fn #130
add stream::from_fn #130
Conversation
Signed-off-by: Yoshua Wuyts <[email protected]>
Signed-off-by: Yoshua Wuyts <[email protected]>
Signed-off-by: Yoshua Wuyts <[email protected]>
Also depends on landing #125 first to make the example work` |
this fix the compile error: laizy@5f6e526 |
@yoshuawuyts There is a higher-performance version: rust-lang/futures-rs#1842 |
Signed-off-by: Yoshua Wuyts <[email protected]>
Signed-off-by: Yoshua Wuyts <[email protected]>
/// if count < 6 { | ||
/// future::ready(Some(count)) | ||
/// } else { | ||
/// future::ready(None) |
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.
We should make this an async closure (closure of async block) instead
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.
Unfortunately, probably the equivalent of this cannot be written by async/await at this time. (see rust-lang/futures-rs#1842 (comment))
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.
(This is one of the unuseful features I mentioned in #129 (comment).)
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.
My understanding is that it can't close over futures, but it can access static
s, which may make it more useful?
I still think Consider the following types of constructors: // We already have this that matches `iter::once`.
fn once<T>(t: T) -> impl Stream<T>;
// What I want and matches `iter::from_fn`.
fn from_fn<T>(f: impl FnOnce() -> T) -> impl Stream<T>;
// What this PR introduces, but names it `from_fn`.
fn from_async_fn<T>(f: impl FnOnce() -> impl Future<Output = T>) -> impl Stream<T>;
// We don't have this yet, but perhaps should.
fn from_future<T>(f: impl Future<Output = T>) -> impl Stream<T>; I find fn once<T>(t: T) -> impl Stream<T> {
from_future(async move { t })
}
fn from_fn<T>(f: impl FnOnce() -> T) -> impl Stream<T> {
from_future(async move { f() })
}
fn from_async_fn<T>(f: impl FnOnce() -> impl Future<Output = T>) -> impl Stream<T> {
from_future(async move { f().await })
} The main hazard of the fn from_async_fn<T>(f: impl AsyncFnOnce() -> T) -> impl Stream<T>; I feel confident about having But I don't feel confident about Constructor |
pub fn from_fn<T, F>(f: F) -> FromFn<F> where
F: FnMut() -> Option<T>, The method I'm proposing here is an async version of that: pub fn from_fn<T, F>(f: F) -> FromFn<F> where
F: FnMut() -> impl Future<Output = Option<T>>, @stjepang this would be equivalent to what you refer to as // These streams are equivalent; we probably should only have the async variant
let mut s1 = stream::from_fn(|| 12);
let mut s2 = stream::from_async_fn(async || 12); You do raise an interesting point about forwards compatibility. Given our signature there wouldn't be a conflict with However concluding; I agree there's no much inherent value to this one method. But I do like the idea of filling in all the blanks so we can point to stdlib to things we're missing (such as async variants of the closures perhaps?) But if we feel uncomfortable with this proposal I suggest we shelve it for now, and focus on things we feel more confident in -- overall this function doesn't seem that important, and we probably shouldn't spend too much time on it. |
I guess my disagreement is around that - an async version of This also got me thinking - an async closure taking no arguments is really not much different from a normal future. Closures with no arguments are typically used to express laziness, for example: // The "else value" gets computed only if `my_option` is `None`.
my_option.unwrap_or_else(|| compute_something_expensive()); But futures are already lazy by their nature, so a closure with no arguments returning a future is two layers of laziness. I find it difficult to come up with a situation where |
Hmm, these are good questions. But I think the differentiator is not in whether they're lazy, but how they work. Consider this scenario: let a = async {};
let b = async || {};
a.await;
a.await; // panic
b().await;
b().await; // ok The difference is that The way I'm thinking about |
Let's revisit this at a later point as it's not that useful right now anyway. Thanks! |
Implements
stream::poll_fn
. Ref #129.Got one compile error around pin that I can't quite figure out; if someone could take a look to help out it'd be much appreciated. Thanks!