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 Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev