On 04 Mar 2014, at 23:05, Daniel Micay <danielmi...@gmail.com> wrote:

> 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.

I assumed the compiler might be able to optimize the extra check away if the 
.next() method gets inlined, but not in the general case. Thus I was trying to 
provide a general solution that wouldn't rely on back-end optimizations. Are 
you saying I assumed wrong?

_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to