On 11.08.2013 12:01, Armin Ronacher wrote:
The way "yield return" works in C# is that it rewrites the code into a state machine behind the scenes. It essentially generates a helper class that encapsulates all the state.

In Rust that's much harder to do due to the type system. Imagine you are doing a yield from a generic hash map. The code that does the rewriting would have to place the hash map itself on the helper struct that holds the state. Which means that the person writing the generator would have to put that into the return value.
I think transforming the yielding function into a state machine, like done in C#, will be the way to go for Rust too.

Rust's type system makes this a bit more complicated than in C#. However, the necessary code transformation has many similarities with supporting closures: * For a closure, the compiler generates a hidden environment struct, containing the captured variables, which is then implicitly passed to the closure function. * For yield, the compiler also generates a hidden struct, implementing the state machine logic, but also 'capturing' the arguments and local parameters of the yielding function.

It is really rather similar as far as the type system is concerned. If we can define sound semantics for closures, we should also be able to define sound semantics for yielding functions. As for having to put the hashmap into the return value, I don't think this is necessary because implementation details of the function are hidden behind the std::Iterator trait.
I imagine, the compiler would do a desugaring like the following:

// Original function
fn yield_some(xs: &'a HashMap<int, float>, a: int, b: int) -> Iterator<float> {
    yield return xs.get(a);
    yield return xs.get(b);
}

// Desugared version
fn yield_some(xs: &'a HashMap<int, float>, a: int, b: int) -> yield_some_iterator<'a> {
    return yield_some_iterator{
        state: 0,
        xs: xs,
        a: a,
        b: b,
    };
}

struct yield_some_iterator<'self> {
    priv state: uint,
priv xs: &'self HashMap<int, float>,
priv a: int,
priv b: int
}

impl std::iterator::Iterator<float> for yield_some_iterator {
    fn next(&self) -> Option<float> {
        match self.state {
            0 => {
                state = 1;
                Some(self.xs.get(self.a))
            }
            1 => {
                state = 2;
                Some(self.xs.get(self.b))
            }
            2 => None
        }
    }
}

As you can see, the compiler substitutes a concrete iterator type. But this iterator type can only ever be accessed through the std::iterator::Iterator interface, which only exposes the return value of the next() method. The internal state of the iterator (such as the hash map) does not have to be considered by the user. (The lifetimes of the yielding function's arguments can, however, influence the lifetime of the resulting iterator, as is the case with closures and captured variables).

I currently have a really hard time thinking about how the c# trick would work :-(
Maybe you do now :)


Aside from this some random notes from Python:

- generators go in both directions in Python which caused problems
  until Python 3.3 where "yield from" (your "yield ..") was introduced
  that expands into a monstrosity that forwards generators into both
  directions.
Can you elaborate on what you mean by "both directions"?

- instead of using "fn" like "def" in Python I would prefer if it was
  an explicit "yield fn" that indicates that the function generates an
  iterator.  The fact that Python reuses "def" is a source of lots of
  bugs and confusion.
I think Rust has an advantage over Python here, in that for every function the return type is explicitly declared. So, if a function returns an Iterator<T> (or better), one does not have to care about whether the function is implemented via 'yield' or if it returns a handwritten iterator. So I think "yield fn" would be redundant here. The type checker won't let through anything confused.


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

Reply via email to