I like the current interface for iterators. :( Couldn't a similar
transformation be done as a special-purpose optimization pass?


On Tue, Mar 4, 2014 at 3:51 PM, Tommi <[email protected]> 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).
>
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
>



-- 
Clark.

Key ID     : 0x78099922
Fingerprint: B292 493C 51AE F3AB D016  DD04 E5E3 C36F 5534 F907
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to