Jacob Holm wrote:
The main thing to note is that the expression form of yield-from is mostly intended to make it easier to have cofunctions that return a value, and that there is a problem with reusing StopIteration for that purpose.
No, I don't think that's where the problem is, if I understand correctly which problem you're referring to. The fact that cofunctions as currently defined in PEP 3152 can't raise StopIteration and have it propagate to the caller is a problem with the use of StopIteration to signal the end of a cofunction. Whether the StopIteration carries a value or not is irrelevant.
And since there are no return values, there is no problem with how "close" should treat them.
There's no problem with that *now*, because close() is currently not defined as returning a value. A problem only arises if we try to overload close() to mean "no more data to send in, give me your result" as well as "bail out now and clean up". And as I pointed out, there are other ways of signalling end of data that work fine with things as they are.
2) In PEP 3152, define "return <value>" in a cofunction to raise a new IterationResult exception with the value.
That would have to apply to *all* forms of return, not just ones with a value.
<var> = (yield from <expr>).value
have the benefit that the PEP 3152 expansion could reraise the actual StopIteration as in:
e = yield from f.__cocall__(*args, **kwargs) if isinstance(e, IterationResult): <var> = e.value else: raise e
There's another way to approach this: define cofunctions so that 'return' in one of its forms is the only way to raise an actual StopIteration, and any explicitly raised StopIteration gets wrapped in something else, such as CoStopIteration. The expansion would then be try: result = yield from f.__cocall__(*args, **kwargs) except CoStopIteration as e: raise e.value where e.value is the original StopIteration instance. This would have the advantage of not requiring any change to yield-from as it stands. -- Greg