rfc:comprehensions

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:comprehensions [2019/03/10 21:36]
crell Fix wiki syntax issues
rfc:comprehensions [2019/04/05 01:10] (current)
crell Revise explanation of generator choice.
Line 31: Line 31:
 </code> </code>
  
-In both cases, ''%%'$gen%%'' is now a generator that will produce double the odd values of $list.  However, the first case uses 38 characters (with spaces) vs 94 characters (with spaces), and is easily compacted onto a single line as opposed to 7.+In both cases, ''%%$gen%%'' is now a generator that will produce double the odd values of $list.  However, the first case uses 38 characters (with spaces) vs 94 characters (with spaces), and is easily compacted onto a single line as opposed to 7.
  
 ===== Proposal ===== ===== Proposal =====
Line 171: Line 171:
   - In most cases it doesn't matter either way. The result will be put into a foreach() loop and that will be the end of it.   - In most cases it doesn't matter either way. The result will be put into a foreach() loop and that will be the end of it.
   - Cases where it does matter are where the list is especially large, or especially expensive to generate and only selected values will be used.  In those cases a generator is superior as it minimizes the memory and CPU usage (respectively) needed to represent values.   - Cases where it does matter are where the list is especially large, or especially expensive to generate and only selected values will be used.  In those cases a generator is superior as it minimizes the memory and CPU usage (respectively) needed to represent values.
-  - If an actual array is desired, converting a generator to an array is a trivial call to ''%%iterator_to_array()%%'' Converting an array to an iterator, while technically easy, has no benefit aside from compatibility with other iterators.  Returning generatorthereforeoffers the most benefit with the fewest limitations.+  - If an actual array is desired, converting a generator to an array is a trivial call to ''%%iterator_to_array()%%'' Converting an array to an iterator, while technically easy, has no benefit aside from compatibility with other iterators. 
 +  - That is, greedy-list value can be composed out of a lazy-list value and a expansion operation.  Howevera lazy-list value cannot be composed from a greedy-list.  That means since both are valuable, the one that provides both via syntactic composition is the superior approach.
   - A compact syntax to produce a generator allows for some nifty functional programming techniques that until now have been verbose to implement for non-array iterators.   - A compact syntax to produce a generator allows for some nifty functional programming techniques that until now have been verbose to implement for non-array iterators.
  
Line 212: Line 213:
  
 $result = array_map(function ($x) { $result = array_map(function ($x) {
-  $x * 2;+  return $x * 2;
 }, $list); }, $list);
  
Line 245: Line 246:
  
 <code php> <code php>
-$list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];+$list = range(1, 10);
  
 // In practice you'd almost always just use a  // In practice you'd almost always just use a 
 // foreach() rather than this monstrosity,  // foreach() rather than this monstrosity, 
 // but I include it for completeness. // but I include it for completeness.
-$result = array_filter(array_map(function ($x) { +$result = array_map(function($x) { 
-  $x * 2; +  return $x * 2; 
-}, $list), function($x) { +}, array_filter(function() {
   return $x % 2;   return $x % 2;
-});+}, $list));
  
 $result = (function() use ($list) { $result = (function() use ($list) {
   foreach ($list as $x) {   foreach ($list as $x) {
-    If ($x % 2) {+    if ($x % 2) {
       yield $x * 2;       yield $x * 2;
     }     }
Line 338: Line 339:
 Numerous languages include a comprehension syntax of some form (https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(list_comprehension)).  Numerous languages include a comprehension syntax of some form (https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(list_comprehension)). 
  
-Two of the languages PHP developers are most likely to also use, JavaScript and Python, feature a very similar syntax.  That is not surprising as Javascript (according to Wikipedia) borrowed its syntax from Pythonmodifying it to the typical syntax Javascript uses for for-each constructs This RFC proposes to do the same, modifying the syntax to fit PHP for-each conventions instead.+The syntax proposed here was initially based on Python'syntax, modified to be more easily handled by PHP's parser and follow more conventional PHP syntax ordering. 
 + 
 +If a more terse syntax that is still lexer-friendly can be proposed that may be adopted instead of the syntax proposed here.
  
 Note that in Python 2.x list comprehensions produce a complete list.  In Python 3.x they produce a generator that will, in turn, produce a complete list.  That change has been a source of incompatibility between Python 2.x and 3.x code.  This RFC proposes using generators exclusively for comprehensions. Note that in Python 2.x list comprehensions produce a complete list.  In Python 3.x they produce a generator that will, in turn, produce a complete list.  That change has been a source of incompatibility between Python 2.x and 3.x code.  This RFC proposes using generators exclusively for comprehensions.
- 
-If a more terse syntax that is still lexer-friendly can be proposed that may be adopted instead of the syntax proposed here. 
  
 ===== Comparison to other proposals ===== ===== Comparison to other proposals =====
  
-The "sort lambda" or "arrow function" RFC has also been discussed in the past.  While the authors of this RFC support both, they should not be viewed as competing but as complementary as they serve different purposes.  While arrow functions would improve the readability of the examples above over their current counterparts, they still would not offer as clean and readable a syntax for the cases where Comprehensions are well suited.  They also would not address the array-or-iterable question for ''%%array_map()%%'' and ''%%array_filter()%%'' Consider this example from above:+The "short lambda" or "arrow function" RFC has also been discussed in the past.  While the authors of this RFC support both, they should not be viewed as competing but as complementary as they serve different purposes.  While arrow functions would improve the readability of the examples above over their current counterparts, they still would not offer as clean and readable a syntax for the cases where Comprehensions are well suited.  They also would not address the array-or-iterable question for ''%%array_map()%%'' and ''%%array_filter()%%'' Consider this example from above:
  
 <code php> <code php>
-$result = array_filter(array_map(function ($x) { +$result = array_map(function($x) { 
-  $x * 2; +  return $x * 2; 
-}, $list), function($x) { +}, array_filter(function() {
   return $x % 2;   return $x % 2;
-});+}, $list));
  
 $result = [for $list as $x if $x % 2 yield $x * 2]; $result = [for $list as $x if $x % 2 yield $x * 2];
Line 359: Line 360:
  
 The arrow function equivalent would be: The arrow function equivalent would be:
 +Which, while unquestionably an improvement over the array_map/array_filter status quo, is still substantially more verbose and hard to read than the proposed Comprehension.
  
 <code php> <code php>
Line 367: Line 369:
 </code> </code>
  
-Which, while unquestionably an improvement over the array_map/array_filter status quo, is still substantially more verbose and hard to read than the proposed Comprehension.+Or potentially: 
 + 
 +<code php> 
 +$result = (fn() => foreach($list as $x) if ($x % 2) yield $x * 2)(); 
 +</code> 
 + 
 +Either is definitely an improvement over the array_map/array_filter status quo, but even the more compact version is longer and entails considerably more syntax salad than a dedicated comprehension syntax.
  
 That said, there are ample other cases where arrow functions would be useful so the adoption of this RFC should in no way be seen to detract from their benefit. That said, there are ample other cases where arrow functions would be useful so the adoption of this RFC should in no way be seen to detract from their benefit.
rfc/comprehensions.1552253791.txt.gz · Last modified: 2019/03/10 21:36 by crell