rfc:short_closures

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:short_closures [2015/05/01 18:39] bwoebirfc:short_closures [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 3: Line 3:
   * Date: 2015-05-01   * Date: 2015-05-01
   * Author: Bob Weinand, bobwei9@hotmail.com   * Author: Bob Weinand, bobwei9@hotmail.com
-  * Status: Draft+  * Status: Declined / Withdrawn in favor of http://wiki.php.net/rfc/arrow_functions
   * First Published at: http://wiki.php.net/rfc/short_closures   * First Published at: http://wiki.php.net/rfc/short_closures
  
Line 28: Line 28:
 </code> </code>
  
-Anonymous functions defined in this way will automatically use() all of the compiled variables in the local scope. See the 'Variable binding' section for more details.+Anonymous functions defined in this way will automatically ''use ()'' all of the (compiledvariables in the Closure body. See the 'Variable binding' section for more details.
  
 ==== Syntax ==== ==== Syntax ====
Line 47: Line 47:
 Omitting the parentheses when the function has multiple parameters will result in a parse error: Omitting the parentheses when the function has multiple parameters will result in a parse error:
 <code php> <code php>
-$x, $y ~> {$x + y}  // Unexpected ','+$x, $y ~> {$x + $y}  // Unexpected ',' 
 +($x, $y) ~> $x + $y // correct
 </code> </code>
  
 Using the return keyword when braces have been omitted, will similarly give a parse error: Using the return keyword when braces have been omitted, will similarly give a parse error:
 <code php> <code php>
-($x, $y) ~> return $x + y; // Unexpected T_RETURN+($x, $y) ~> return $x + $y; // Unexpected T_RETURN 
 +($x, $y) ~> { return $x + $y; } // correct
 </code> </code>
  
-Concrete syntax is (~> is right associative with lowest possible associativity):+In case of no parameters, an empty parenthesis pair is needed. 
 +<code php> 
 +~> 2 * 3; // Unexpected T_TILDED_ARROW 
 +() ~> 2 * 3; // correct, will return 6 when called 
 +</code> 
 + 
 +Concrete syntax is (~> is right associative with lowest possible precedence):
 <code> <code>
   ( parameter_list ) ~> expression   ( parameter_list ) ~> expression
Line 68: Line 76:
  
 When a bare expression is used as second parameter, its result will be the return value of the Closure. When a bare expression is used as second parameter, its result will be the return value of the Closure.
 +
 +Also, parameter_list does //not// include default values nor type hints. See also the 'Type Hints and Return Types' section at the bottom. 
 +
 +//Discussion Point: the { statements } syntax//
 +This RFC stance is that chained short Closures followed by a full Closure would look quite weird: ''$foo ~> $bar ~> function ($baz) use ($foo, $bar) { /* ... */ }''. Instead of a nicer ''$foo ~> $bar ~> $baz ~> { /* ... */ }''. Which is why they are supported. That syntax is **not** an invitation to randomly abuse it and use it in totally inappropriate places.
 +
 +//Discussion Point: single parameter//
 +While it might appear not consistent, with any other number of parameters, a lot of languages having extra short Closures allow this. Also, Closures with just one parameter are relatively common, so this RFC author thinks it is worth supporting that.
  
 ==== Variable binding ==== ==== Variable binding ====
-The position of this RFC is that the shorthand syntax is to allow anonymous functions to be used as easily as possible. Therefore, rather than requiring individual variables be bound to the closure through the ''use ($x)'' syntax, instead all variables in the scope where the anonymous function is defined will automatically be bound to the anonymous function closure.+The position of this RFC is that the shorthand syntax is to allow anonymous functions to be used as easily as possible. Therefore, rather than requiring individual variables be bound to the closure through the ''use ($x)'' syntax, instead all variables used in the body of the anonymous function will automatically be bound to the anonymous function closure from the defining scope.
  
-For example:+The variable binding is always **by value**. There are no implicit references. If these are needed, the current syntax with ''use ()'' can be used.
  
 +For example:
 <code php> <code php>
 $a = 1; $a = 1;
Line 98: Line 115:
  
 ==== Array sort with user function ==== ==== Array sort with user function ====
-Sort ''$array'' which contains objects which have a property named ''val'' in reverse.+Sort ''$array'' which contains objects which have a property named ''val''.
  
 Current syntax: Current syntax:
Line 104: Line 121:
 usort($array,  usort($array, 
  function($a, $b) {  function($a, $b) {
- return -($a->val <=> $b->val)+ return $a->val <=> $b->val; 
  }  }
 ); );
Line 111: Line 128:
 New syntax: New syntax:
 <code php> <code php>
-usort($array, ($a, $b) ~> -($a->val <=> $b->val));+usort($array, ($a, $b) ~> $a->val <=> $b->val);
 </code> </code>
  
Line 119: Line 136:
 function sumEventScores($events, $scores) { function sumEventScores($events, $scores) {
     $types = array_map(     $types = array_map(
-        function ($event) {+        function($event) {
             return $event['type'];             return $event['type'];
         },         },
Line 127: Line 144:
     return array_reduce(     return array_reduce(
         $types,         $types,
-        function ($sum, $type) use ($scores) {+        function($sum, $type) use ($scores) {
             return $sum + $scores[$type];             return $sum + $scores[$type];
         }         }
Line 165: Line 182:
  
 sumEventScores($events, $scores); sumEventScores($events, $scores);
 +</code>
 +
 +==== Lazy evaluation ====
 +It may be necessary to have code only evaluated under specific conditions, like debugging code:
 +<code php>
 +function runDebug(callable $func) {
 +    /* only run under debug situations, but don't let it interrupt program flow, just log it */
 +    if (DEBUG) {
 +        try {
 +            $func();
 +        } catch (Exception $e) { /*... */ }
 +    }
 +}
 +
 +$myFile = "/etc/passwd";
 +
 +/* Old code */
 +runDebug(function() use ($myFile) { /* yeah, we have to use use ($myFile) here, which isn't really helpful in this context */ 
 +    if (!file_exists($myFile)) {
 +        throw new Exception("File $myFile does not exist...");
 +    }
 +});
 +
 +/* New code */
 +runDebug(() ~> {
 +    if (!file_exists($myFile)) {
 +        throw new Exception("File $myFile does not exist...");
 +    }
 +});
 +
 +/* still continue here, unlike an assert which would unwind the stack frame here ... */
 </code> </code>
  
 ==== Partial application ==== ==== Partial application ====
-The short hand syntax makes it easier to write functional code like a reducer by using the ability of shorthand anonymous functions to be chained together easily.+The shorthand syntax makes it easier to write functional code like a reducer by using the ability of shorthand anonymous functions to be chained together easily.
  
 Current syntax: Current syntax:
Line 174: Line 222:
 function reduce(callable $fn) { function reduce(callable $fn) {
     return function($initial) use ($fn) {     return function($initial) use ($fn) {
-        return function ($input) use ($fn, $initial) {+        return function($input) use ($fn, $initial) {
             $accumulator = $initial;             $accumulator = $initial;
             foreach ($input as $value) {             foreach ($input as $value) {
Line 213: Line 261:
 return [$x => $x * 2]; return [$x => $x * 2];
 </code> </code>
 +
 +Additionally, I was asked to not reuse the ''%%==>%%'' syntax (http://chat.stackoverflow.com/transcript/message/25421648#25421648) as Hack is already using it. Hence ''~>'' looks like a great alternative.
 +
 +Also, Hack has some possibilities of typing here, which do not work with PHP, due to technical reasons. Regarding forward compatibility, we might have to choose another syntax than Hack here to resolve these issues. It'd end up being the same operator, with a very similar syntax, potentially confusing. Furthermore using the same syntax than Hack here might lead users to expect types working here and getting really confused.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 228: Line 280:
     private $bar:     private $bar:
  
-    getBar ~> $this->bar;+    getBar() ~> $this->bar;
     setBar($bar) ~> $this->bar = $bar;     setBar($bar) ~> $this->bar = $bar;
 } }
Line 243: Line 295:
 As an alternative, the current syntax for defining Closures still can be used here.  As an alternative, the current syntax for defining Closures still can be used here. 
  
-===== Proposed Voting Choices =====+===== Vote =====
 This RFC is a language change and as such needs a 2/3 majority. This RFC is a language change and as such needs a 2/3 majority.
  
-It will be a simple yes/no vote.+Voting opened September 22th, 2015 and will remain open until October 2nd, 2015. 
 + 
 +<doodle title="Short Closures" auth="bwoebi" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle>
  
 ===== Patch ===== ===== Patch =====
 Pull request is at https://github.com/php/php-src/pull/1254 Pull request is at https://github.com/php/php-src/pull/1254
rfc/short_closures.1430505582.txt.gz · Last modified: 2017/09/22 13:28 (external edit)