Hi,
On 11/08/2013 15:43, Michael Woerister wrote:
Maybe you do now :)
I see where this is going, that's actually not too bad. So essentially
it would generate some anonymous struct and impl.
Can you elaborate on what you mean by "both directions"?
Python has this inheritance tree (virtual):
Iterable
Iterator
Generator
An iterable is defined as a class with a __iter__() that returns an
iterator. An iterator is defined as an iterable that returns itself and
also has a __next__ method which either returns a value or raises a
StopIterator.
A generator is a separate beast that is produced by the compiled if it
spots a function with a 'yield' expression. A generator also exposes
the iterator protocol but actually does more. If you call __next__() on
a generator is equivalent to calling .send(None). Essentially in Python
a generator can produce values, but also get data sent:
def g():
num = 0
while 1:
next_num = (yield num)
if next_num is not None:
num = next_num
else:
num += 1
If you just iterate over it, it's an eternal iterator that produces ever
increasing numbers. If you however call .send(NUM) on it, it sets the
internal counter to NUM and yields the same number back next iteration.
The ugly side effect of this is that you now need to forward these
generators in both directions. PEP 0380 explains how that looks like.
eg: for item in x(): yield item is not good enough, as it now throws
away the return value from yield.
The reason I'm bringing this up is because in case Rust ever wants to
gain support for bidirectional generators it should from the very start
have something like a "yield from" to not break the reverse forwarding.
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.
You would think, neither do you in Python. The problem is actually not
so much the consuming of the function but the writing of it. In a
regular function you have execution as the function is called. In a
generator function the execution immediately suspends until you call
next(). It's very confusing for beginners and has caused in many, many
broken WSGI applications in Python (WSGI is the Python web abstraction
protocol that uses iterators).
Even more than that, how do you make an empty generator? There is a lot
of code that does any of those:
def iter_nothing():
return iter([])
def iter_nothing():
if False:
yield None
Lastly, in Python 3 we now are getting async IO support through
generators and the frameworks do weird things to make generator and
regular functions decorated with the same decorator, behave similarly in
case someone deletes the last 'yield' from the function. An explicit
'yield fn' outside of the function solves this case, where a function
degrades to not having any yield expressions any more.
Yes, in theory you could make a function that returns nil but is
declared as returning an iterator, just return the empty iterator for
that type, but that seems wrong.
Regards,
Armin
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev