Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Mark Shannon

Stefan Behnel wrote:

Hi,

I found a problem in the current yield from implementation that I think
is worth discussing:

http://bugs.python.org/issue14220


[snip]

I've been experimenting with the implementation of PEP 380, and I found 
a couple of interesting things.


First of all, the semantics described in the PEP do not match the tests.
If you substitute the supposedly semantically equivalent code
based on normal yields for each yield from in the test code
(Lib/test/test_pep380.py) and run it, then it fails.

My second experiment involved stripping away all the code relating to 
yield from outside of the interpreter and changing the YIELD_FROM
bytecode to repeat itself, by setting the last instruction to the 
instruction immediately before itself.

To do this I added 4 lines of code and removed over 120 lines :)

This fails many of the tests*, but works for the most straightforward
use cases. Many of these failures seem to me to be more 'natural' than 
the current behaviour


It might be possible to fix most, or all?, of the other failures
by compiling yield from into a two opcode sequence:
YIELD_FROM_START and YIELD_FROM_REPEAT.
Both opcodes should be reasonably simple and __next__() and send() would 
not have to worry about the subiterator, although close() and throw()

might (the subiterator would be top-of-stack in the generator's frame)

Overall the semantics of PEP 380 seem far too complex,
trying to do several things at once.
An example:
Plain yield makes no distinction between a receiving a None and any 
other value, so send(None) and __next__() are the same. Yield from
makes this distinction so has to test for None, meaning the semantics of 
send now changes with its argument.


I would recommend changing one of two things in the PEP:
Either, close and throw should not close/throw in subiterators
(this would simplify the semantics and implementation immensely)
Or, only allow subgenerators, not subiterators
(this would fix the next/send problem).

I would also suggest a change in implementation to perform all yields
within the interpreter. A simpler implementation is likely to be a
more reliable one.

Finally, the PEP itself makes no mention of coroutines, stackless or 
greenlet in the alternatives or criticisms section. Perhaps it should.


Cheers,
Mark.

*Tests in PEP 380. It passes all other tests.
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Nick Coghlan
On Thu, Mar 8, 2012 at 9:52 PM, Mark Shannon m...@hotpy.org wrote:
 I would recommend changing one of two things in the PEP:
 Either, close and throw should not close/throw in subiterators
 (this would simplify the semantics and implementation immensely)
 Or, only allow subgenerators, not subiterators
 (this would fix the next/send problem).

Either of those changes would completely defeat the point of the PEP.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Nick Coghlan
On Thu, Mar 8, 2012 at 9:52 PM, Mark Shannon m...@hotpy.org wrote:
 First of all, the semantics described in the PEP do not match the tests.
 If you substitute the supposedly semantically equivalent code
 based on normal yields for each yield from in the test code
 (Lib/test/test_pep380.py) and run it, then it fails.

What's more important is whether or not it matches the semantics of
inlining the subgenerator bodies. The expansion in the PEP was an
attempt to define a way to achieve that in current Python without
interpreter support.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Mark Shannon

Nick Coghlan wrote:

On Thu, Mar 8, 2012 at 9:52 PM, Mark Shannon m...@hotpy.org wrote:

First of all, the semantics described in the PEP do not match the tests.
If you substitute the supposedly semantically equivalent code
based on normal yields for each yield from in the test code
(Lib/test/test_pep380.py) and run it, then it fails.


What's more important is whether or not it matches the semantics of
inlining the subgenerator bodies. The expansion in the PEP was an
attempt to define a way to achieve that in current Python without
interpreter support.


So yield from X means inline X here, if X is a generator.
That is much, much easier to understand than the big block of
code in the PEP.
It really ought say that yield from is equivalent to inlining
in the PEP.

Cheers,
Mark

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Nick Coghlan
On Thu, Mar 8, 2012 at 11:45 PM, Mark Shannon m...@hotpy.org wrote:
 It really ought say that yield from is equivalent to inlining
 in the PEP.

That's what the motivation section is about. There's also an entire
subsection called The Refactoring Principle that describes this
intent. However, we needed something more concrete to flesh out the
original implementation details, which is what the code equivalent was
designed to provide (it was also designed to point out that the days
of you can just use a simple for loop actually went away when PEP
342 was implemented).

Now, it may be that we fixed things during implementation that should
be reflected back into the formal semantic spec in the PEP - so if you
can point out specific cases where what we implemented doesn't match
the nominal behaviour, I'm open to updating the PEP accordingly. (Of
course, if there are any tests that fail solely due to the two known
differences in semantics that are already noted in the PEP, they don't
count).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Stefan Behnel
Stefan Behnel, 07.03.2012 21:40:
 I found a problem in the current yield from implementation

... and here's another one, also in genobject.c:


int
PyGen_FetchStopIterationValue(PyObject **pvalue) {
PyObject *et, *ev, *tb;
PyObject *value = NULL;

if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
PyErr_Fetch(et, ev, tb);
Py_XDECREF(et);
Py_XDECREF(tb);
if (ev) {
value = ((PyStopIterationObject *)ev)-value;
Py_INCREF(value);
Py_DECREF(ev);
}
} else if (PyErr_Occurred()) {
return -1;
}
if (value == NULL) {
value = Py_None;
Py_INCREF(value);
}
*pvalue = value;
return 0;
}


When the StopIteration was set using PyErr_SetObject(), ev points to the
value, not the exception instance, so this code lacks exception
normalisation. I use slightly different code in Cython (which needs to be
compatible with Py2.x), but CPython 3.3 could do something along these lines:


if (ev) {
if (PyObject_IsInstance(ev, PyExc_StopIteration)) {
value = ((PyStopIterationObject *)ev)-value;
Py_INCREF(value); // or maybe XINCREF()?
Py_DECREF(ev);
} else {
/* PyErr_SetObject() puts the value directly into ev */
value = ev;
}
} else ...


Would that be acceptable for CPython as well or would you prefer full
fledged normalisation?

Stefan

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Benjamin Peterson
2012/3/8 Stefan Behnel stefan...@behnel.de:
 Would that be acceptable for CPython as well or would you prefer full
 fledged normalisation?

I think we have to normalize for correctness. Consider that it may be
some StopIteration subclass which set value on construction.


-- 
Regards,
Benjamin
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Antoine Pitrou
On Thu, 8 Mar 2012 14:36:06 -0600
Benjamin Peterson benja...@python.org wrote:
 2012/3/8 Stefan Behnel stefan...@behnel.de:
  Would that be acceptable for CPython as well or would you prefer full
  fledged normalisation?
 
 I think we have to normalize for correctness. Consider that it may be
 some StopIteration subclass which set value on construction.

Perhaps it would be time to drop the whole delayed normalization thing,
provided the benchmarks don't exhibit a slowdown? It complicates a lot
of code paths.

cheers

Antoine.


___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-08 Thread Benjamin Peterson
2012/3/8 Antoine Pitrou solip...@pitrou.net:
 On Thu, 8 Mar 2012 14:36:06 -0600
 Benjamin Peterson benja...@python.org wrote:
 2012/3/8 Stefan Behnel stefan...@behnel.de:
  Would that be acceptable for CPython as well or would you prefer full
  fledged normalisation?

 I think we have to normalize for correctness. Consider that it may be
 some StopIteration subclass which set value on construction.

 Perhaps it would be time to drop the whole delayed normalization thing,
 provided the benchmarks don't exhibit a slowdown? It complicates a lot
 of code paths.

+1 Also, it delays errors from exception initialization to arbitrary points.

-- 
Regards,
Benjamin
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] problem with recursive yield from delegation

2012-03-07 Thread Stefan Behnel
Hi,

I found a problem in the current yield from implementation that I think
is worth discussing:

http://bugs.python.org/issue14220

Test code:

def g1():
yield y1
yield from g2()
yield y4

def g2():
yield y2
try:
yield from gi
except ValueError:
pass  # catch already running error
yield y3

gi = g1()
for y in gi:
print(Yielded: %s % (y,))

This is what it currently does:

1) g1() delegates to a new g2(), propagates its y2 value and asks for the
next value

2) g2 delegates back to the g1 instance and asks for its next value

3) Python sees the active delegation in g1 and asks g2 for its next value

4) g2 sees that it's already running and throws an exception

Ok so far. Now:

5) the exception is propagated into g1 at call level 3) instead of the
original requestor g2 one level above

6) g1 undelegates and terminates by the exception

7) g2 catches the exception, yields y3 and then terminates normally

8) g1 gets control back but has already terminated and does nothing

Effect: g1 does not yield y4 anymore.

The problem is in steps 5) and 6), which are handled by g1 at the wrong
call level. They shouldn't lead to undelegation and termination in g1, just
to an exception being raised in g2.

I ran into this while trying to adapt the implementation for Cython, which
has a different generator type implementation but otherwise uses more or
less the same code now. But I'm not sure how to fix this one without major
changes to the implementation, especially not without special casing the
generator type on delegation (which won't work because CPython doesn't know
about Cython generators). Any ideas?

Stefan

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-07 Thread Benjamin Peterson
2012/3/7 Stefan Behnel stefan...@behnel.de:
 The problem is in steps 5) and 6), which are handled by g1 at the wrong
 call level. They shouldn't lead to undelegation and termination in g1, just
 to an exception being raised in g2.

That looks wrong indeed.


 I ran into this while trying to adapt the implementation for Cython, which
 has a different generator type implementation but otherwise uses more or
 less the same code now. But I'm not sure how to fix this one without major
 changes to the implementation

Cython's or CPython's implementation?


-- 
Regards,
Benjamin
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-07 Thread Nick Coghlan
On Thu, Mar 8, 2012 at 6:40 AM, Stefan Behnel stefan...@behnel.de wrote:
 I ran into this while trying to adapt the implementation for Cython, which
 has a different generator type implementation but otherwise uses more or
 less the same code now. But I'm not sure how to fix this one without major
 changes to the implementation, especially not without special casing the
 generator type on delegation (which won't work because CPython doesn't know
 about Cython generators). Any ideas?

After tinkering with it a bit, a couple of my original guesses as to
the underlying problem were clearly wrong. I'm moving house next week,
so it'll be a while before I get to look at it in detail, but I added
Mark Shannon to the issue's nosy list. He's been working on a few
patches lately to clean up generator related state handling in
general, so he may have some insight into this.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-07 Thread Benjamin Peterson
2012/3/7 Benjamin Peterson benja...@python.org:
 2012/3/7 Stefan Behnel stefan...@behnel.de:
 The problem is in steps 5) and 6), which are handled by g1 at the wrong
 call level. They shouldn't lead to undelegation and termination in g1, just
 to an exception being raised in g2.

 That looks wrong indeed.

Fixed as of 3357eac1ba62


-- 
Regards,
Benjamin
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-07 Thread Nick Coghlan
On Thu, Mar 8, 2012 at 10:00 AM, Benjamin Peterson benja...@python.org wrote:
 2012/3/7 Benjamin Peterson benja...@python.org:
 2012/3/7 Stefan Behnel stefan...@behnel.de:
 The problem is in steps 5) and 6), which are handled by g1 at the wrong
 call level. They shouldn't lead to undelegation and termination in g1, just
 to an exception being raised in g2.

 That looks wrong indeed.

 Fixed as of 3357eac1ba62

Thanks. And, since the fix was entirely internal to the generator
implementation, Stefan should be right for the Cython generators, too.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] problem with recursive yield from delegation

2012-03-07 Thread Jim J. Jewett


http://mail.python.org/pipermail/python-dev/2012-March/117396.html
Stefan Behnel posted:

 I found a problem in the current yield from implementation ...

[paraphrasing]

g1 yields from g2
g2 yields from g1
XXX python follows the existing delegation without checking re-entrancy
g2 (2nd call) checks re-entrancy, and raises an exception
g1 (2nd call) gets to handle the exception, and doesn't
g2 (1st call) gets to handle the exception, and does


How is this a problem?

Re-entering a generator is a bug.  Python caught it and raised an
appropriate exception.

It would be nice if python caught the generator cycle as soon as it was
created, just as it would be nice if reference cycles were collected as
soon as they became garbage.  But python doesn't promise to catch cycles
immediately, and the checks required to do so would slow down all code,
so in practice the checks are delayed.


-jJ

-- 

If there are still threading problems with my replies, please 
email me with details, so that I can try to resolve them.  -jJ

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] problem with recursive yield from delegation

2012-03-07 Thread Nick Coghlan
On Thu, Mar 8, 2012 at 10:32 AM, Jim J. Jewett jimjjew...@gmail.com wrote:
 How is this a problem?

 Re-entering a generator is a bug.  Python caught it and raised an
 appropriate exception.

No, the problem was that the interpreter screwed up the state of the
generators while attempting to deal with the erroneous reentry. The
ValueError *should* just be caught and completely suppressed by the
try/except block, but that wasn't quite happening properly - the
failed attempt at reentry left the generators in a dodgy state (which
is why the subsequent 3 was being produced, but then the expected
final 4 vanished into the electronic ether).

Benjamin figured out where the generator's reentrancy check was going
wrong, so Stefan's example should do the right thing in the next alpha
(i.e. the ValueError will still get raised and suppressed by the
try/except block, the inner generator will complete, but the outer
generator will also continue on to produce the final value).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com