On 2010-10-30 01:03, Greg Ewing wrote:
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.
Exactly.
Whether the StopIteration carries a value or not is irrelevant.
It is relevant if we later want to distinguish between "return" and "raise StopIteration".
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.
That is what I meant. We were discussing whwther to add a new feature to PEP 380 inspired by having "return <value>" in generators. If we dropped "return <value>" from PEP 380 (with the intent of adding it to PEP 3152 instead), so would the basis for the new feature. End of discussion... AFAICT, adding these features in a consistent way is a lot easier in the context of PEP 3152.
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.
Of course.
<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.
That's just ugly... I realize it could work, but I think that makes *both* PEPs more complex than necessary. My suggestion is to cut/change some features from PEP 380 that are in the way and then add them in a cleaner way to PEP 3152. This should simplify both PEPs, at the cost of reopening some of the earlier discussions. - Jacob