<div dir="ltr"><div class="gmail_default" style="font-family:monospace,monospace"><span style="font-family:arial,sans-serif">On Mon, Oct 9, 2017 at 9:46 AM, Nick Coghlan </span><span dir="ltr" style="font-family:arial,sans-serif"><<a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>></span><span style="font-family:arial,sans-serif"> wrote:</span><br></div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>On 8 October 2017 at 08:40, Koos Zevenhoven <span dir="ltr"><<a href="mailto:k7hoven@gmail.com" target="_blank">k7hoven@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><span class="gmail-m_7154132099627044838m_1967755331403670313gmail-"><div style="font-family:monospace,monospace"><span style="font-family:arial,sans-serif">On Sun, Oct 8, 2017 at 12:16 AM, Nathaniel Smith </span><span dir="ltr" style="font-family:arial,sans-serif"><<a href="mailto:njs@pobox.com" target="_blank">njs@pobox.com</a>></span><span style="font-family:arial,sans-serif"> wrote:</span><br></div></span><div class="gmail_extra"><div class="gmail_quote"><span class="gmail-m_7154132099627044838m_1967755331403670313gmail-"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><span class="gmail-m_7154132099627044838m_1967755331403670313gmail-m_-8202751580970511457gmail-"><div class="gmail_extra" dir="auto"><div class="gmail_quote">On Oct 7, 2017 12:20, "Koos Zevenhoven" <<a href="mailto:k7hoven@gmail.com" target="_blank">k7hoven@gmail.com</a>> wrote:<blockquote class="gmail-m_7154132099627044838m_1967755331403670313gmail-m_-8202751580970511457gmail-m_-8935789036438109007quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div class="gmail-m_7154132099627044838m_1967755331403670313gmail-m_-8202751580970511457gmail-m_-8935789036438109007elided-text"><div><br></div></div><div><div style="font-family:monospace,monospace">Unfortunately, we actually need a third kind of generator semantics, something like this:</div><div style="font-family:monospace,monospace"><br></div><div style="font-family:monospace,monospace">@contextvars.caller_context</div><div style="font-family:monospace,monospace">def genfunc():</div><div style="font-family:monospace,monospace"> assert cvar.value is the_value</div><div style="font-family:monospace,monospace"> yield</div><div style="font-family:monospace,monospace"> assert cvar.value is the_value</div><div style="font-family:monospace,monospace"><br></div><div style="font-family:monospace,monospace">with cvar.assign(the_value):</div><div style="font-family:monospace,monospace"> gen = genfunc()</div><div style="font-family:monospace,monospace"><br></div><div style="font-family:monospace,monospace">next(gen)</div><div style="font-family:monospace,monospace"><br></div><div style="font-family:monospace,monospace">with cvar.assign(1234567890):</div><div style="font-family:monospace,monospace"> try:</div><div style="font-family:monospace,monospace"> next(gen)</div><div style="font-family:monospace,monospace"> except StopIteration:</div><div style="font-family:monospace,monospace"> pass</div><div style="font-family:monospace,monospace"><br></div><div style="font-family:monospace,monospace">Nick, Yury and I (and Nathaniel, Guido, Jim, ...?) somehow just narrowly missed the reasons for this in discussions related to PEP 550. Perhaps because we had mostly been looking at it from an async angle.</div></div></div></div></div></blockquote></div></div><div dir="auto"><br></div></span><div dir="auto">That's certainly a semantics that one can write down (and it's what the very first version of PEP 550 did), </div></div></blockquote><div><br></div></span><div><div style="font-family:monospace,monospace">I do remember Yury mentioning that the first draft of PEP 550 captured something when the generator function was called. I think I started reading the discussions after that had already been removed, so I don't know exactly what it was. But I doubt that it was *exactly* the above, because PEP 550 uses set and get operations instead of "assignment contexts" like PEP 555 (this one) does. </div></div></div></div></div></blockquote><div><br></div></span><div>We didn't forget it, we just don't think it's very useful. </div></div></div></div></blockquote><div><br></div><div><div class="gmail_default" style="font-family:monospace,monospace">Yeah, I'm not surprised you remember that :). But while none of us saw a good enough reason for it at that moment, I have come to think we absolutely need it. We need both the forest and the trees.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">Sure, if you think of next() as being a simple function call that does something that involves state, then you might want the other semantics (with PEP 555, that situation would look like):</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">def do_stuff_with_side_effects():</div><div class="gmail_default" style="font-family:monospace,monospace"> with cvar.assign(value):</div><div class="gmail_default" style="font-family:monospace,monospace"> return next(global_gen_containing_<wbr>state)</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">Now stuff happens within next(..), and whatever happens in next(..) is expected to see the cvar assignment.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">However, probably much more often, one just thinks of next(..) as "getting the next value", although some computations happen under the hood that one doesn't need to care about. </div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">As we all know, in the real world, the use case is usually just to generate the Fibonacci sequence ;). And when you call fibonacci(), the whole sequence should already be determined. You just evaluate the sequence lazily by calling next() each time you want a new number. It may not even be obvious when the computations are made:</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">fib_cache = [0, 1]</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">def fibonacci():</div><div class="gmail_default" style="font-family:monospace,monospace"> for i in itertools.counter():<br></div><div class="gmail_default" style="font-family:monospace,monospace"> if i < len(fib_cache):<br></div><div class="gmail_default" style="font-family:monospace,monospace"> yield fib_cache[i]</div><div class="gmail_default" style="font-family:monospace,monospace"> else:</div><div class="gmail_default" style="font-family:monospace,monospace"> # not calculated before</div><div class="gmail_default" style="font-family:monospace,monospace"> new = sum(fib_cache[-2:])</div><div class="gmail_default" style="font-family:monospace,monospace"> fib_cache.append(new)</div><div class="gmail_default" style="font-family:monospace,monospace"> yield new</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace"># (function above is thread-unsafe, for clarity)<br></div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">(Important:) So in *any* situation, where you want the outer context to affect the stuff inside the generator through next(), like in the `do_stuff_with_side_effects` example, <i>the author of the generator function needs to know about it</i>. And then it is ok to require that the author uses a decorator on the generator function. </div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">But when you just generate a pre-determined set of numbers (like fibonacci), the implementation of the generator function should not matter, but if the outer context leaks in through next(..), the internal implementation does matters, and the abstraction is leaky. I don't want to give the leaky things by default.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">––Koos</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div></div><div> </div></div>-- <br><div class="gmail-m_7154132099627044838gmail_signature">+ Koos Zevenhoven + <a href="http://twitter.com/k7hoven" target="_blank">http://twitter.com/k7hoven</a> +</div>
</div></div>