On 04/03/14 03:51 PM, Tommi wrote:
> The problem:
>
> When you iterate over elements of an Iterator in a for-loop, you effectively
> end up checking whether the Iterator is empty or not twice per element, i.e.
> once inside the Iterator's "next" method and once in doing match for the
> Option returned by the "next" method.
>
> Example:
>
> struct Digits {
> n: int
> }
>
> impl Iterator<int> for Digits {
> fn next(&mut self) -> Option<int> {
> if self.n < 10 { // Checking whether Iterator is empty or not
> let ret = Some(self.n);
> self.n += 1;
> ret
> }
> else { None }
> }
> }
>
> fn main() {
> let mut itr = Digits { n: 0 };
>
> for i in itr {
> println!("{}", i);
> }
> }
>
> I assume that the for-loop above is effectively the same as the following:
>
> fn main() {
> let mut itr = Digits { n: 0 };
>
> loop {
> let x = itr.next(); // The first check happens here
> match x { // And the second check happens here
> Some(i) => println!("{}", i),
> None => break
> }
> }
> }
>
> The proposed solution:
>
> We add to the language the ability to set trait-methods private (accessible
> only to default methods of that trait). We add two new private methods to the
> Iterator<A> trait, namely "is_empty" and "next_unwrapped". Then we provide a
> default implementation for the next method of Iterator<A> trait. It would
> look something like the following:
>
> pub trait Iterator<A> {
> priv fn is_empty(&self) -> bool;
>
> priv fn next_unwrapped(&mut self) -> A;
>
> fn next(&mut self) -> Option<A> {
> if self.is_empty() {
> None
> }
> else {
> Some(self.next_unwrapped())
> }
> }
> }
>
> Then the Iterator implementation for Digits we had before would become
> something like the following:
>
> impl Iterator<int> for Digits {
> // Since we're not overriding the default implementation for the "next"
> method,
> // we must implement the private methods which the "next" method uses:
>
> priv fn is_empty(&self) -> bool {
> self.n > 9
> }
>
> priv fn next_unwrapped(&mut self) -> int {
> let ret = self.n;
> self.n += 1;
> ret
> }
> }
>
> And the for-loop we had in the beginning could be translated under the hood
> to something like the following:
>
> fn main() {
> let mut itr = Digits { n: 0 };
>
> loop {
> if itr.is_empty() {
> break;
> }
> else {
> let i = itr.next_unwrapped();
> println!("{}", i);
> }
> }
> }
>
> Now we're checking whether or not the iterator is empty only once per
> element. And notice also that the code above would not compile because the
> is_empty() and next_unwrapped() methods are private to the Iterator trait,
> but the compiler is allowed to secretly call them when you write the above
> main() using the regular for-loop syntax:
>
> fn main() {
> let mut itr = Digits { n: 0 };
>
> for i in itr {
> println!("{}", i);
> }
> }
>
> P.S.
>
> A while ago I suggested adding private trait-methods for a different use case
> (namely the non-virtual interface idiom).There will be no benefit in optimized builds from changing the iterator design. The only performance issue is caused by a known and fixable limitation, which is that rustc is not communicating when pointers are known to be non-null.
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
