Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:62240 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 82622 invoked from network); 18 Aug 2012 13:39:04 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 18 Aug 2012 13:39:04 -0000 Authentication-Results: pb1.pair.com smtp.mail=nikita.ppv@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=nikita.ppv@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.217.170 as permitted sender) X-PHP-List-Original-Sender: nikita.ppv@gmail.com X-Host-Fingerprint: 209.85.217.170 mail-lb0-f170.google.com Received: from [209.85.217.170] ([209.85.217.170:65263] helo=mail-lb0-f170.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 2B/F6-31572-7FA9F205 for ; Sat, 18 Aug 2012 09:39:04 -0400 Received: by lbbgp3 with SMTP id gp3so2706161lbb.29 for ; Sat, 18 Aug 2012 06:39:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=zmmOs1xkSJfhBza4ny5HILydz0JDnR3NF3NKaIB/Gro=; b=h1zyTWmGsSl6boJkSOEk84fsGdgZCgzMtHL1pq6VkY+w9dCzHmbaMIiVIb0w/upVt2 OBDHZLClKSWCHNLWN/99nCVvGFSLG3Z09DK4tAkLutx/7LqGOFG3nMzyPK5Z8SqLrBcX J3Vvb0RTD8k3pBWJ/nfHDTVKhnXUb3tB2k2s5gRMviA0yNq5w2/rACA+XvqN+MXvLMsb VdmdO89ooNXNRhprADR5kYhWdJ7okYIR3bCiulkhQZYnBveUtn1K6P5XIIyu/+kIzGEc Uw64kAP3TBH7/38BlPiB5jO1SglCCB7Kv8wt13sCztg69NEloAFQ+8cJerYkPgeFXckY Anfg== MIME-Version: 1.0 Received: by 10.112.37.8 with SMTP id u8mr3698879lbj.30.1345297140863; Sat, 18 Aug 2012 06:39:00 -0700 (PDT) Received: by 10.152.122.51 with HTTP; Sat, 18 Aug 2012 06:39:00 -0700 (PDT) In-Reply-To: References: <500EE3B9.8010902@ajf.me> <500EEA76.1030407@ajf.me> <5010138D.5050804@ajf.me> <501015B9.6050704@ajf.me> <501058B9.5050004@lsces.co.uk> <501249B6.5070507@lsces.co.uk> <50128825.4020902@lsces.co.uk> <50231FAD.40104@garfieldtech.com> Date: Sat, 18 Aug 2012 15:39:00 +0200 Message-ID: To: Sherif Ramadan Cc: Larry Garfield , internals@lists.php.net Content-Type: text/plain; charset=ISO-8859-1 Subject: Re: [PHP-DEV] Re: Generators in PHP From: nikita.ppv@gmail.com (Nikita Popov) On Thu, Aug 9, 2012 at 4:49 AM, Sherif Ramadan wrote: >> >> One question, though: It looks based on the voting like finally {} blocks >> are going in. So... what should happen in the following situation: >> >> function stuff() { >> try { >> foreach (range(1, 100) as $i) { >> yield $i; >> } >> } >> finally { >> print "All done"; >> } >> } >> >> Does "All done" get printed once, or 101 times? Similarly: >> >> function things() { >> $i = 1; >> try { >> while (true) { >> yield $i++; >> } >> } >> finally { >> print "All done"; >> } >> } >> >> That will run indefinitely. So will "All done" ever print, or does that >> finally become unreachable? >> >> (I have no clue what the behavior "should" be in these cases, just that it >> should be sorted out sooner rather than later.) >> > > > Based on my understanding of both RFCs, I don't see that this would be > a conflict or lead to unexpected behavior. As stated by the generators > RFC: "When you first call the generator function ($lines = > getLinesFromFile($fileName)) the passed argument is bound, but nothing > of the code is actually executed. Instead the function directly > returns a Generator object.". > > So in the event we are calling the function stuff(), nothing should > actually be executed, and as we iterate over the traversable object > the generator should be "passing control back and forth between the > generator and the calling code". This would be indicated by the > "yield" keyword present in the function. Meaning you should see the > expected result and finally should only ever be called once in your > first example. > > As for you second example... Obviously if you've created an infinite > loop you've made everything outside of the loop unreachable, whether > you're using generators or not. > > However, I'll let the author of the RFC provide any clarification or > corrections where I might be wrong. Ooops, accidentially hit "Send" too early. So again: Yes, that is basically right. The one interesting case that arises when using generators is what happens when you close a generator before it is finished. E.g. in the function mentioned above: function stuff() { try { foreach (range(1, 100) as $i) { yield $i; } } finally { print "All done"; } } If you now create the generator, do 50 iterations and then close it: $gen = stuff(); foreach (stuff() as $i) { if ($i == 50) break; } unset($gen); In that case the code (normally) would never reach the "finally" clause, simply because it isn't resumed anymore. Python solved this problem by throwing a GeneratorExitException into the generator when it is closed. So when unset($gen) is called an exception is thrown at the yield-stackframe and the generator resumed. This then invokes usual exception bubbling and runs finally clauses. When the GeneratorExitException bubbles out of the generator function is implicitly caught and discarded. For PHP we would need to have some similar behavior. PHP's current exception model is incompatible with GeneratorExitException (because PHP does not have BaseExceptions). So what I'd probably do instead is monkeypatch a ZEND_RETURN opcode at the current execution position and resume the generator. This would then invoke any finally clauses through the usual processes. This should be a very transparent process that "just works" without the need for any strange exception hacks. Nikita