On 29/04/2016 20:58, Sara Golemon wrote:
This is one of my favorites out of HackLang. It's pure syntactic
sugar, but it goes a long way towards improving readability.
https://wiki.php.net/rfc/pipe-operator
I like this idea, for the same reason I like chained method calls - the
code reads left to right, rather than inside to outside.
One problem with that, though, is that the output from the whole
expression ends up on the left, if you want to save it out somewhere. To
take an example from the RFC:
$ret = scandir($arg)
|> array_filter($$, function($x) { return $x !== '.' && $x != '..'; })
|> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$)
|> getFileArg($$)
|> array_merge($ret, $$);
Once you've read through this whole sequence of steps, you have to go
right back to the beginning to find that the result is saved into "$ret".
It's not clear to me whether the RHS in the current implementation can
be an arbitrary expression, since all the examples use function calls at
every step; would this be valid?
scandir($arg)
|> array_filter($$, function($x) { return $x !== '.' && $x != '..'; })
|> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$)
|> getFileArg($$)
|> array_merge($ret, $$)
|> ($ret = $$);
Even if it is, it looks a bit ugly; what about adding an extra operator
for assignment, like "|>=" or "|=>"?
scandir($arg)
|> array_filter($$, function($x) { return $x !== '.' && $x != '..'; })
|> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$)
|> getFileArg($$)
|> array_merge($ret, $$)
|=> $ret;
I think this would also improve the situation around debugging and
error-handling, because you could more freely mix piped and non-piped
code by "breaking the chain" with an assigment.
Let's say I want to add a condition just before getFileArg(); with the
current version I've got to:
- go to the beginning of the chain, and assign to something other than $ret
- go to where I want to break the chain, and reintroduce the $ret assignment
- add my check in the gap, using the variable I just added at the
beginning of the chain
$fileList = scandir($arg)
|> array_filter($$, function($x) { return $x !== '.' && $x != '..'; })
|> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$);
if ( someCheck($fileList) {
something();
}
$ret = getFileArg($$)
|> array_merge($ret, $$);
The syntax is fighting me here, making me jump around the code. But if
assignment was always on the end of the chain, I would only need to make
changes at the point where I was breaking the chain. The basic pattern
would be:
|=> $tempVar; // terminate the chain and capture the value
// do stuff with $tempVar
$tempVar // restart the chain
So:
scandir($arg)
|> array_filter($$, function($x) { return $x !== '.' && $x != '..'; })
|> array_map(function ($x) use ($arg) { return $arg . '/' . $x; }, $$)
|=> $fileList;
if ( someCheck($fileList) {
something();
}
$fileList
|> getFileArg($$)
|> array_merge($ret, $$)
|=> $ret;
If I don't need the condition any more, I can delete lines 4 to 8, and
I've got back my original chain.
Again, I'm not clear from the RFC if it's currently valid to use
"return" in a piped expression, but it makes sense to me for the same
reasons outlined above. This example is from the Hack docs, where it
puts the "return" on the left, breaking the flow:
return $arr
|> array_map($x ==> $x->getNumber(), $$)
|> array_filter($$, $x ==> $x % 2 == 0)
|> count($$);
To me, that reads better as:
$arr
|> array_map($x ==> $x->getNumber(), $$)
|> array_filter($$, $x ==> $x % 2 == 0)
|> count($$)
|> return $$;
Personally, I'd quite like it if the chain *had* to have a left-to-right
form like this, and always constituted a statement, not an expression.
Regards,
--
Rowan Collins
[IMSoP]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php