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

Implement iter::Sum and iter::Product for Result #38580

Merged
merged 1 commit into from
Jan 11, 2017

Conversation

shepmaster
Copy link
Member

This introduces a private iterator adapter ResultShunt, which allows
treating an iterator of Result<T, E> as an iterator of T.

@rust-highfive
Copy link
Collaborator

r? @aturon

(rust_highfive has picked a reviewer for you, use r? to override)

@shepmaster
Copy link
Member Author

/cc @bluss

@shepmaster
Copy link
Member Author

shepmaster commented Dec 23, 2016

I'm opening this PR to see if we think it's small enough to merge, wants an RFC, or doesn't belong at all. If we think it should be merged, I can create a stability tracking issue and add the appropriate tests added.

This allows code like

use std::io;
use std::io::prelude::*;

fn main() {
    let stdin = io::stdin();
    let sum: Result<usize, _> = stdin.lock().lines().map(|l| {
        l.map(|l| l.len())
    }).sum();
    println!("{:?}", sum);
}

Likewise, I can add an implementation for Product added.

@frewsxcv frewsxcv added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Dec 23, 2016
@aturon
Copy link
Member

aturon commented Dec 24, 2016

Ooh, neat!

Trait impls like this are instantly stable, regardless of the stability attribute, unfortunately. So we'll need libs team consensus to move forward. This doesn't require an RFC, though.

Libs team: please signal agreement/disagreement to this idea in principle. I'll work with @shepmaster to get the PR itself in shape if we want to do this.

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Dec 24, 2016

Team member @aturon has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once these reviewers reach consensus, 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.

@Mark-Simulacrum
Copy link
Member

This feels somewhat similar to the trait @eddyb and I added to rustc::ty::context, which allows transparently collecting iterators of Result<T, E> or T into a R or Result<R, E> (i.e., it allows passing a function similar to map to convert the value). I'm not sure if that's really relevant, but thought I'd mention it at least in passing since it felt similar.

I feel like it would be nice to make the reconstruction step obvious. That is, make let sum = shunt.by_ref().sum(); happen within a closure, for example, the sum impl would be rewritten like below. I guess the ergonomics of using it are slightly worse, but I feel like the API is somewhat safer, since you cannot lose the error accidentally.

impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
    where T: Sum<U>,
{
    fn sum<I>(iter: I) -> Result<T, E>
        where I: Iterator<Item = Result<U, E>>,
    {
        ResultShunt::process(iter, |iter| iter.sum())
    }
}

@sfackler
Copy link
Member

ResultShunt is a private type, so there shouldn't ever be any uses of it other than this one method I think.

@shepmaster
Copy link
Member Author

ResultShunt is private, but it's a pattern that I think I'll make strong use of. I CCed @bluss in the hopes that it can make its way into itertools (and maybe eventually be public in the standard library?). Making it less likely to misuse in general seems like a good thing to me.

@sfackler
Copy link
Member

(See also https://crates.io/crates/fallible-iterator for all of your fallible iteration needs)

@shepmaster shepmaster changed the title Implement iter::Sum for Result Implement iter::Sum and iter::Product for Result Dec 24, 2016
@shepmaster
Copy link
Member Author

shepmaster commented Dec 26, 2016

I've added the suggested process method which also had the benefit of DRYing up the call sites. 👍

@shepmaster
Copy link
Member Author

This feels somewhat similar to the trait @eddyb and I added to rustc::ty::context

I've now found and read InternAs / InternIteratorElement, and I agree that while in the same area, it seems distinct and solves a different problem. My brain can't fully brain if one is more powerful / generic than the other.

@eddyb
Copy link
Member

eddyb commented Dec 26, 2016

They're all monads, basically. Except Haskell oversimplifies and Iterator is... a monadic type class? And I have no real suggestions on how to actually generically express such things, it all gives me headaches.

@eddyb
Copy link
Member

eddyb commented Dec 26, 2016

On a more serious note, rust-lang/rfcs#1672 would go a long way making at least ad-hoc abstractions over T and Result<T, E> simpler (e.g. InternIteratorElement wouldn't be needed).

@shepmaster
Copy link
Member Author

2 week gentle reminder for @brson

}
}

#[unstable(feature = "result-sum", issue = "0")]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are these tagged unstable? Isn't this an insta-stable implementation?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure how impls are usually tagged.

Copy link
Member Author

Choose a reason for hiding this comment

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

Isn't this an insta-stable implementation?

Yep! It was a misunderstanding of mine. As @aturon said:

Trait impls like this are instantly stable, regardless of the stability attribute, unfortunately. So we'll need libs team consensus to move forward. This doesn't require an RFC, though.

Libs team: please signal agreement/disagreement to this idea in principle. I'll work with @shepmaster to get the PR itself in shape if we want to do this.

So I was waiting for those checkboxes before removing that. 😸

@brson
Copy link
Contributor

brson commented Jan 7, 2017

I guess this is fine by me, but it seems to be solving a specific case of a more general problem, that of doing something useful with collections of results. That is a problem I have a lot, but specifically summing results is not.

@shepmaster
Copy link
Member Author

solving a specific case of a more general problem, that of doing something useful with collections of results

Absolutely! Although I feel like I'm usually dealing with iterators of Results. My secret hope is that ResultShunt (or some improved version) can help in these cases by allowing the "inner" iterator to not even know about the Result while still preserving the rich iterator-ness.

(And after typing all of that, the monad name-dropping from @eddyb seems painfully obvious in retrospect)

@shepmaster
Copy link
Member Author

I'll work with @shepmaster to get the PR itself in shape if we want to do this.

@aturon what changes would you like to see done? The stability attributes need to be updated, certainly; what's appropriate to do there?

@rfcbot
Copy link

rfcbot commented Jan 9, 2017

🔔 This is now entering its final comment period, as per the review above. 🔔

psst @aturon, I wasn't able to add the final-comment-period label, please do so.

@alexcrichton
Copy link
Member

@shepmaster from my look I think the only thing that needs to be done here is update the stability attributes. Want to file an issue and cc me? I'll be sure to tag it and we can r+ this then

@aturon
Copy link
Member

aturon commented Jan 10, 2017

Yeah, I didn't have any specific concerns; land when ready!

@alexcrichton
Copy link
Member

Oh actually sorry I forgot that impls are insta-stable, so we don't need the rigamarole with unstable issues at all! Want to just switch these tags to stable and we can land?

@shepmaster
Copy link
Member Author

I forgot that impls are insta-stable

I was a bit confused why we were making a tracking issue, but figured I'd just go along and learn as I went. ^_^

@shepmaster
Copy link
Member Author

shepmaster commented Jan 10, 2017

these tags to stable and we can land?

What feature and version should I use for the stability attributes?

@alexcrichton
Copy link
Member

I believe the master branch is 1.16.0

@shepmaster
Copy link
Member Author

I believe the master branch is 1.16.0

Sounds good; I reused the iter_arith_traits feature; hope that's OK!

@alexcrichton
Copy link
Member

Oh I think reusing an existing feature causes problems with make tidy, but it's ok to just manufacture a new feature out of thin air.

This introduces a private iterator adapter `ResultShunt`, which allows
treating an iterator of `Result<T, E>` as an iterator of `T`.
@shepmaster
Copy link
Member Author

reusing an existing feature causes problems with make tidy, but it's ok to just manufacture a new feature out of thin air.

yup and yup!

@alexcrichton
Copy link
Member

@bors: r+

@bors
Copy link
Contributor

bors commented Jan 10, 2017

📌 Commit 23715d3 has been approved by alexcrichton

@bors
Copy link
Contributor

bors commented Jan 10, 2017

⌛ Testing commit 23715d3 with merge a180dd7...

@bors
Copy link
Contributor

bors commented Jan 10, 2017

💔 Test failed - status-travis

@alexcrichton
Copy link
Member

alexcrichton commented Jan 10, 2017 via email

@bors
Copy link
Contributor

bors commented Jan 10, 2017

⌛ Testing commit 23715d3 with merge 0500fbf...

bors added a commit that referenced this pull request Jan 10, 2017
Implement `iter::Sum` and `iter::Product` for `Result`

This introduces a private iterator adapter `ResultShunt`, which allows
treating an iterator of `Result<T, E>` as an iterator of `T`.
@bors
Copy link
Contributor

bors commented Jan 11, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: alexcrichton
Pushing 0500fbf to master...

@bors bors merged commit 23715d3 into rust-lang:master Jan 11, 2017
jsonn pushed a commit to jsonn/pkgsrc that referenced this pull request Mar 20, 2017
Version 1.16.0 (2017-03-16)
===========================

Language
--------

* Lifetimes in statics and consts default to `'static`. [RFC 1623]
* [The compiler's `dead_code` lint now accounts for type aliases][38051].
* [Uninhabitable enums (those without any variants) no longer permit wildcard
  match patterns][38069]
* [Clean up semantics of `self` in an import list][38313]
* [`Self` may appear in `impl` headers][38920]
* [`Self` may appear in struct expressions][39282]

Compiler
--------

* [`rustc` now supports `--emit=metadata`, which causes rustc to emit
  a `.rmeta` file containing only crate metadata][38571]. This can be
  used by tools like the Rust Language Service to perform
  metadata-only builds.
* [Levenshtein based typo suggestions now work in most places, while
  previously they worked only for fields and sometimes for local
  variables][38927]. Together with the overhaul of "no
  resolution"/"unexpected resolution" errors (#[38154]) they result in
  large and systematic improvement in resolution diagnostics.
* [Fix `transmute::<T, U>` where `T` requires a bigger alignment than
  `U`][38670]
* [rustc: use -Xlinker when specifying an rpath with ',' in it][38798]
* [`rustc` no longer attempts to provide "consider using an explicit
  lifetime" suggestions][37057]. They were inaccurate.

Stabilized APIs
---------------

* [`VecDeque::truncate`]
* [`VecDeque::resize`]
* [`String::insert_str`]
* [`Duration::checked_add`]
* [`Duration::checked_sub`]
* [`Duration::checked_div`]
* [`Duration::checked_mul`]
* [`str::replacen`]
* [`str::repeat`]
* [`SocketAddr::is_ipv4`]
* [`SocketAddr::is_ipv6`]
* [`IpAddr::is_ipv4`]
* [`IpAddr::is_ipv6`]
* [`Vec::dedup_by`]
* [`Vec::dedup_by_key`]
* [`Result::unwrap_or_default`]
* [`<*const T>::wrapping_offset`]
* [`<*mut T>::wrapping_offset`]
* `CommandExt::creation_flags`
* [`File::set_permissions`]
* [`String::split_off`]

Libraries
---------

* [`[T]::binary_search` and `[T]::binary_search_by_key` now take
  their argument by `Borrow` parameter][37761]
* [All public types in std implement `Debug`][38006]
* [`IpAddr` implements `From<Ipv4Addr>` and `From<Ipv6Addr>`][38327]
* [`Ipv6Addr` implements `From<[u16; 8]>`][38131]
* [Ctrl-Z returns from `Stdin.read()` when reading from the console on
  Windows][38274]
* [std: Fix partial writes in `LineWriter`][38062]
* [std: Clamp max read/write sizes on Unix][38062]
* [Use more specific panic message for `&str` slicing errors][38066]
* [`TcpListener::set_only_v6` is deprecated][38304]. This
  functionality cannot be achieved in std currently.
* [`writeln!`, like `println!`, now accepts a form with no string
  or formatting arguments, to just print a newline][38469]
* [Implement `iter::Sum` and `iter::Product` for `Result`][38580]
* [Reduce the size of static data in `std_unicode::tables`][38781]
* [`char::EscapeDebug`, `EscapeDefault`, `EscapeUnicode`,
  `CaseMappingIter`, `ToLowercase`, `ToUppercase`, implement
  `Display`][38909]
* [`Duration` implements `Sum`][38712]
* [`String` implements `ToSocketAddrs`][39048]

Cargo
-----

* [The `cargo check` command does a type check of a project without
  building it][cargo/3296]
* [crates.io will display CI badges from Travis and AppVeyor, if
  specified in Cargo.toml][cargo/3546]
* [crates.io will display categories listed in Cargo.toml][cargo/3301]
* [Compilation profiles accept integer values for `debug`, in addition
  to `true` and `false`. These are passed to `rustc` as the value to
  `-C debuginfo`][cargo/3534]
* [Implement `cargo --version --verbose`][cargo/3604]
* [All builds now output 'dep-info' build dependencies compatible with
  make and ninja][cargo/3557]
* [Build all workspace members with `build --all`][cargo/3511]
* [Document all workspace members with `doc --all`][cargo/3515]
* [Path deps outside workspace are not members][cargo/3443]

Misc
----

* [`rustdoc` has a `--sysroot` argument that, like `rustc`, specifies
  the path to the Rust implementation][38589]
* [The `armv7-linux-androideabi` target no longer enables NEON
  extensions, per Google's ABI guide][38413]
* [The stock standard library can be compiled for Redox OS][38401]
* [Rust has initial SPARC support][38726]. Tier 3. No builds
  available.
* [Rust has experimental support for Nvidia PTX][38559]. Tier 3. No
  builds available.
* [Fix backtraces on i686-pc-windows-gnu by disabling FPO][39379]

Compatibility Notes
-------------------

* [Uninhabitable enums (those without any variants) no longer permit wildcard
  match patterns][38069]
* In this release, references to uninhabited types can not be
  pattern-matched. This was accidentally allowed in 1.15.
* [The compiler's `dead_code` lint now accounts for type aliases][38051].
* [Ctrl-Z returns from `Stdin.read()` when reading from the console on
  Windows][38274]
* [Clean up semantics of `self` in an import list][38313]

[37057]: rust-lang/rust#37057
[37761]: rust-lang/rust#37761
[38006]: rust-lang/rust#38006
[38051]: rust-lang/rust#38051
[38062]: rust-lang/rust#38062
[38062]: rust-lang/rust#38622
[38066]: rust-lang/rust#38066
[38069]: rust-lang/rust#38069
[38131]: rust-lang/rust#38131
[38154]: rust-lang/rust#38154
[38274]: rust-lang/rust#38274
[38304]: rust-lang/rust#38304
[38313]: rust-lang/rust#38313
[38314]: rust-lang/rust#38314
[38327]: rust-lang/rust#38327
[38401]: rust-lang/rust#38401
[38413]: rust-lang/rust#38413
[38469]: rust-lang/rust#38469
[38559]: rust-lang/rust#38559
[38571]: rust-lang/rust#38571
[38580]: rust-lang/rust#38580
[38589]: rust-lang/rust#38589
[38670]: rust-lang/rust#38670
[38712]: rust-lang/rust#38712
[38726]: rust-lang/rust#38726
[38781]: rust-lang/rust#38781
[38798]: rust-lang/rust#38798
[38909]: rust-lang/rust#38909
[38920]: rust-lang/rust#38920
[38927]: rust-lang/rust#38927
[39048]: rust-lang/rust#39048
[39282]: rust-lang/rust#39282
[39379]: rust-lang/rust#39379
[`<*const T>::wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset
[`<*mut T>::wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset
[`Duration::checked_add`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_add
[`Duration::checked_div`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_div
[`Duration::checked_mul`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_mul
[`Duration::checked_sub`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.checked_sub
[`File::set_permissions`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.set_permissions
[`IpAddr::is_ipv4`]: https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_ipv4
[`IpAddr::is_ipv6`]: https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_ipv6
[`Result::unwrap_or_default`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_default
[`SocketAddr::is_ipv4`]: https://doc.rust-lang.org/std/net/enum.SocketAddr.html#method.is_ipv4
[`SocketAddr::is_ipv6`]: https://doc.rust-lang.org/std/net/enum.SocketAddr.html#method.is_ipv6
[`String::insert_str`]: https://doc.rust-lang.org/std/string/struct.String.html#method.insert_str
[`String::split_off`]: https://doc.rust-lang.org/std/string/struct.String.html#method.split_off
[`Vec::dedup_by_key`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dedup_by_key
[`Vec::dedup_by`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dedup_by
[`VecDeque::resize`]:  https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html#method.resize
[`VecDeque::truncate`]: https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html#method.truncate
[`str::repeat`]: https://doc.rust-lang.org/std/primitive.str.html#method.repeat
[`str::replacen`]: https://doc.rust-lang.org/std/primitive.str.html#method.replacen
[cargo/3296]: rust-lang/cargo#3296
[cargo/3301]: rust-lang/cargo#3301
[cargo/3443]: rust-lang/cargo#3443
[cargo/3511]: rust-lang/cargo#3511
[cargo/3515]: rust-lang/cargo#3515
[cargo/3534]: rust-lang/cargo#3534
[cargo/3546]: rust-lang/cargo#3546
[cargo/3557]: rust-lang/cargo#3557
[cargo/3604]: rust-lang/cargo#3604
[RFC 1623]: https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md
@shepmaster shepmaster deleted the result-sum branch April 25, 2018 19:28
Centril added a commit to Centril/rust that referenced this pull request May 29, 2019
…r=dtolnay

Implement `iter::Sum` and `iter::Product` for `Option`

This is similar to the existing implementation for `Result`. It will take each item into the accumulator unless a `None` is returned.

I based a lot of this on rust-lang#38580. From that discussion it didn't seem like this addition would be too controversial or difficult. One thing I still don't understand is picking the values for the `stable` attribute. This is my first non-documentation PR for rust so I am open to any feedback on improvements.
Centril added a commit to Centril/rust that referenced this pull request May 29, 2019
…r=dtolnay

Implement `iter::Sum` and `iter::Product` for `Option`

This is similar to the existing implementation for `Result`. It will take each item into the accumulator unless a `None` is returned.

I based a lot of this on rust-lang#38580. From that discussion it didn't seem like this addition would be too controversial or difficult. One thing I still don't understand is picking the values for the `stable` attribute. This is my first non-documentation PR for rust so I am open to any feedback on improvements.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.