rfc:generator-return-expressions

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
rfc:generator-return-expressions [2015/02/19 23:34]
rdlowrey s/background/concurrent/
rfc:generator-return-expressions [2017/09/22 13:28] (current)
Line 2: Line 2:
   * Version: 0.1   * Version: 0.1
   * Date: 2015-02-18   * Date: 2015-02-18
-  * Authors: Daniel Lowrey <rdlowrey@php.net>Nikita Popov <nikic@php.net> +  * Author: Daniel Lowrey <rdlowrey@php.net> 
-  * Status: Under Discussion+  * Contributors: Nikita Popov <nikic@php.net> 
 +  * Status: Implemented (in PHP 7.0)
   * First Published at: http://wiki.php.net/rfc/generator-return-expressions   * First Published at: http://wiki.php.net/rfc/generator-return-expressions
  
Line 9: Line 10:
  
  
-PHP's generators are unequivocally useful both for iteration and cooperative multi-tasking. However, the inability of generator functions to specify return values artificially limits their usefulness for multitasking in coroutine contexts. This RFC proposes the ability to both specify and access Generator return values while laying the groundwork for future sub-generator returns.+PHP's generators are unequivocally useful both for iteration and cooperative multi-tasking. However, the inability of generator functions to specify return values artificially limits their usefulness for multitasking in coroutine contexts. This RFC proposes the ability to both specify and access Generator return values while laying the groundwork for future sub-generator returns. The proposal is a prerequisite for the conceptually related [[rfc:generator-delegation|Generator Delegation]] RFC.
  
  
Line 31: Line 32:
  
  
-1. Modify generator functions to allow ''return'' expressions.+  * Modify generator functions to allow ''return'' expressions.
  
-2. Expose ''Generator::getReturn()'' to retrieve returned values.+  * Expose ''Generator::getReturn()'' to retrieve returned values.
  
-3. Calling ''Generator::getReturn()'' while a generator is still valid will throw. This is consistent with the behavior seen when calling ''Generator::rewind()'' after iteration has already started. The logic behind throwing when the generator remains valid is that we should prevent calling code from mistaking a yet-to-be-computed return value (''null'') for the actual return value. Invoking ''Generator::getReturn()'' on a still-valid generator or generator that has thrown represents a logic error and is treated as such.+  * Calling ''Generator::getReturn()'' while a generator is still valid will throw. This is consistent with the behavior seen when calling ''Generator::rewind()'' after iteration has already started. The logic behind this decision is that we should prevent calling code from mistaking a yet-to-be-computed return value (''null'') for the actual return value. This proposal's position is that invoking ''Generator::getReturn()'' on a still-valid generator (or one that has thrown) is a logic error.
  
  
Line 52: Line 53:
  
 $bar = foo(); $bar = foo();
-do +foreach ($bar as $element) 
-    echo $bar->current(), "\n"+    echo $element, "\n"; 
-    $bar->next()+}
-while ($bar->valid());+
  
 var_dump($bar->getReturn()); var_dump($bar->getReturn());
Line 135: Line 135:
 ===== Use-Case: Coroutine Return Values ===== ===== Use-Case: Coroutine Return Values =====
  
-Generators are particularly useful for their ability to pause execution and resume at a later time. This capacity allows applications to cooperatively multitask discrete units of processing work. However, the inability to explicitly return values leaves coroutines in a situation where they're able to process concurrent tasks but have no standard way to access the results of those computations. Consider:+Generators are particularly useful for their ability to suspend execution and resume at a later time. This capacity allows applications to cooperatively multitask discrete units of processing work. However, the inability to explicitly return values leaves coroutines in a situation where they're able to process concurrent tasks but have no standard way to access the results of those computations. Consider:
  
 <code php> <code php>
Line 170: Line 170:
     return $bar + 42; // unambiguous execution "result"     return $bar + 42; // unambiguous execution "result"
 }; };
 +?>
 </code> </code>
 +
 +
 +===== Reference Returns =====
 +
 +Generators currently utilize the `&` operator to indicate values will be yielded by-reference:
 +
 +<code php>
 +<?php
 +function &gen_reference() {
 +    $value = 3;
 +
 +    while ($value > 0) {
 +        yield $value;
 +    }
 +}
 +
 +foreach (gen_reference() as &$number) {
 +    echo (--$number).'... ';
 +}
 +?>
 +</code>
 +
 +As ''function&'' is already in place to modify yield values we have no way to differentiate between by-reference yield values and by-reference return values. While it would be possible to use ''function&'' to mark returns as by-reference, this proposal's position is that no correlation exists between the "reference-ness" of yielded values and return values. Instead of introducing new tokens or syntax to allow by-reference returns this proposal //always// uses ''ZVAL_COPY'' on return zvals. In short: by-reference returns are not supported in generator return expressions.
  
  
Line 224: Line 248:
 ===== Future Scope ===== ===== Future Scope =====
  
-The proposed behavior lays the groundwork for future sub-generator functionality using ''yield from'' or ''yield *'' to break apart functional units into multiple generators. In such cases a sub-generator's return value is sent to the parent generator upon completed iteration. ''return'' expression capability is needed to implement this behavior in future PHP versions.+The proposed behavior lays the groundwork for future sub-generator functionality using ''yield from'' to break apart functional units into multiple generators. In such cases a sub-generator's return value is sent to the parent generator upon completed iteration. ''return'' expression capability is needed to implement this behavior in future PHP versions.
  
 A brief example of how ''yield from'' might be implemented in the future using the return expressions proposed in the current RFC: A brief example of how ''yield from'' might be implemented in the future using the return expressions proposed in the current RFC:
Line 232: Line 256:
 function foo() { function foo() {
     yield 1;     yield 1;
-    $subReturn = yield from bar()+    return yield from bar();
-    yield $subReturn;+
 } }
  
Line 243: Line 266:
  
 $baz = foo(); $baz = foo();
- +foreach ($baz as $element) 
-do +    echo $element, "\n"; 
-    echo $baz->current(), "\n"; +} 
-    $baz->next(); +echo $baz->getReturn(), "\n";
-} while($baz->valid());+
  
 // 1 // 1
Line 256: Line 278:
  
  
-===== Proposed Voting Choices ===== +===== Vote =====
-Two voting choices are proposed:+
  
-1. **YES**, allow Generator return expressions and ''expose Generator::getReturn()'' to access returned values in PHP 7 +Voting begins 2015-03-09 and ends on 2015-03-16.
- +
-2**NO**, do not modify existing Generator behavior+
  
 A 2/3 "Yes" vote is required to implement this proposal. A 2/3 "Yes" vote is required to implement this proposal.
 +
 +
 +<doodle title="Allow Generator return expressions in PHP7" auth="rdlowrey" voteType="single" closed="true">
 +   * Yes
 +   * No
 +</doodle>
 +
 +. Vote closed at 14:50 UTC 2015-03-17.
 +
 +**NOTE:** the related [[rfc:generator-delegation|Generator Delegation]] RFC depends on the acceptance of this proposal.
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
Line 279: Line 308:
 [[https://docs.python.org/3/whatsnew/3.3.html#pep-380|New in Python 3.3: yield from]] [[https://docs.python.org/3/whatsnew/3.3.html#pep-380|New in Python 3.3: yield from]]
  
-===== Rejected Features ===== 
-TBD 
rfc/generator-return-expressions.1424388843.txt.gz · Last modified: 2017/09/22 13:28 (external edit)