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

Reply via email to