Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function concatenation. At the time, the main thrust of the feedback was "cool, like, but we need partial function application first so that the syntax for callables isn't so crappy."
The PFA RFC is winding down now and is looking quite good, so it's time to revisit pipes.
https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have updated it against the latest master. I also updated the RFC to use more examples that assume PFA, as the result is legit much nicer. i also tested it locally with a combined partials-and-pipes branch to make sure they play nicely together, and they do. (Yay!) Assuming PFA passes I will include those tests in the pipes branch before this one goes to a vote.
--
Larry Garfield
larry@garfieldtech.com
On Mon, Jun 7, 2021 at 9:03 PM Larry Garfield larry@garfieldtech.com
wrote:
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax for
callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time to
revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use more
examples that assume PFA, as the result is legit much nicer. i also tested
it locally with a combined partials-and-pipes branch to make sure they play
nicely together, and they do. (Yay!) Assuming PFA passes I will include
those tests in the pipes branch before this one goes to a vote.
FTR, there are several typos in the "Hello World" examples (strtotupper,
htmlentities). Also, these examples will not work as written because
explode()
expects two arguments and will fail if you pass only one:
https://3v4l.org/tLO0s. I wonder what the correct version of the pipe
example (the one that uses strings as callbacks) would look like, given
that you have to pass two arguments for explode()
?
--
Thank you and best regards,
Eugene Leonovich
On Mon, Jun 7, 2021 at 9:03 PM Larry Garfield larry@garfieldtech.com
wrote:Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax for
callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time to
revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use more
examples that assume PFA, as the result is legit much nicer. i also tested
it locally with a combined partials-and-pipes branch to make sure they play
nicely together, and they do. (Yay!) Assuming PFA passes I will include
those tests in the pipes branch before this one goes to a vote.FTR, there are several typos in the "Hello World" examples (strtotupper,
htmlentities). Also, these examples will not work as written because
explode()
expects two arguments and will fail if you pass only one:
https://3v4l.org/tLO0s. I wonder what the correct version of the pipe
example (the one that uses strings as callbacks) would look like, given
that you have to pass two arguments forexplode()
?
Hm. You're right. It used to, but it's been a very long time since explode()
allowed an empty split, apparently. I updated the example to use str_split, which is what I'd intended to do in this case. Thanks.
If you wanted to explode with a separator in a non-PFA pipes world, you'd need to wrap it in an arrow function. (Hence why a PFA-world pipe is all around better.)
--Larry Garfield
Hi,
On Tue, Jun 8, 2021 at 12:09 AM Larry Garfield larry@garfieldtech.com
wrote:
On Mon, Jun 7, 2021 at 9:03 PM Larry Garfield larry@garfieldtech.com
wrote:FTR, there are several typos in the "Hello World" examples
(strtotupper,
htmlentities). Also, these examples will not work as written because
explode()
expects two arguments and will fail if you pass only one:
https://3v4l.org/tLO0s.Hm. You're right. It used to, but it's been a very long time since
explode()
allowed an empty split, apparently. I updated the example to use
str_split, which is what I'd intended to do in this case. Thanks.
Are you thinking to implode()
? Anyway, you forgot to update one
explode(?)
to str_split(?)
, and also, the first fn($v) => 'strtoupper'
should be just 'strtoupper'
.
About Haskell, rather than (or in addition to) the function composition
[not "concatenation"] (.), I would mention the reverse application operator
(&):
https://hackage.haskell.org/package/base-4.15.0.0/docs/Data-Function.html#v:-38-
One thing I note is that even with PFA, some examples still need an arrow
function, e.g. the PSR-7 one:
ServerRequest::fromGlobals()
|> authenticate(?)
|> $router->resolveAction(?)
|> fn($request) => $request->getAttribute('action')($request)
/* ... */;
while in Hack you would write it as:
ServerRequest::fromGlobals()
|> authenticate($$)
|> $router->resolveAction($$)
|> $$->getAttribute('action')($$)
/* ... */;
Also, quoting from
https://wiki.php.net/rfc/first_class_callable_syntax#partial_function_application
:
"""
Both approaches to the pipe operator have their advantages. The $$ based
variant allows using more than plain function calls in each pipeline step
(e.g. you could have $$->getName() as a step, something not possible with
PFA), and is also trivially free. A PFA-based optimization would entail
significant overhead relative to simple function calls, unless special
optimization for the pipe operator usage is introduced (which may not be
possible, depending on precise semantics).
"""
Could you (or Nikita) expand a bit on this (esp. the advantages of the PFA
approach / disadvantages of Hack's approach)?
Regards,
--
Guilliam Xavier
Hm. You're right. It used to, but it's been a very long time since
explode()
allowed an empty split, apparently. I updated the example to use
str_split, which is what I'd intended to do in this case. Thanks.Are you thinking to
implode()
? Anyway, you forgot to update one
explode(?)
tostr_split(?)
, and also, the firstfn($v) => 'strtoupper'
should be just'strtoupper'
.
I deliberately made that example extra verbose to show how ugly it can get, but I can shorten it.
About Haskell, rather than (or in addition to) the function composition
[not "concatenation"] (.), I would mention the reverse application operator
(&):
https://hackage.haskell.org/package/base-4.15.0.0/docs/Data-Function.html#v:-38-One thing I note is that even with PFA, some examples still need an arrow
function, e.g. the PSR-7 one:ServerRequest::fromGlobals() |> authenticate(?) |> $router->resolveAction(?) |> fn($request) => $request->getAttribute('action')($request) /* ... */;
while in Hack you would write it as:
ServerRequest::fromGlobals() |> authenticate($$) |> $router->resolveAction($$) |> $$->getAttribute('action')($$) /* ... */;
Also, quoting from
https://wiki.php.net/rfc/first_class_callable_syntax#partial_function_application
:"""
Both approaches to the pipe operator have their advantages. The $$ based
variant allows using more than plain function calls in each pipeline step
(e.g. you could have $$->getName() as a step, something not possible with
PFA), and is also trivially free. A PFA-based optimization would entail
significant overhead relative to simple function calls, unless special
optimization for the pipe operator usage is introduced (which may not be
possible, depending on precise semantics).
"""Could you (or Nikita) expand a bit on this (esp. the advantages of the PFA
approach / disadvantages of Hack's approach)?Regards,
It's true PFA doesn't cover every possible RHS of pipes. In practice, I think using the piped value as an object on which to invoke a method is the only major gap. Normally in functional code you would use a lens in that case, which (if I am understanding those correctly; that's roughly at the edge of my functional understanding) is essentially a function call that wraps accessing a property or calling a method so that it feels more functional, and thus pipes cleanly.
However, piping with callables has a number of advantages.
-
The implementation is vastly simpler. It's simple enough that even I can manage it, whereas Hack-style would be more considerably implementation work.
-
I would argue it's more flexible. Once you start thinking of callables/functions in a first class way, producing functions on the fly that do what you want becomes natural, and fits better with a pipe-to-callable model. For instance, the comprehension-esque example (which I suspect will be one of the most common use cases of pipes) is far cleaner with a callable, as it can obviate any question about parameter order.
Another example I threw together last night is this proof of concept last night, which works when pipes, enums, and partials are combined. I don't think Hack-style would be capable of this, at least not as elegantly.
https://gist.github.com/Crell/e484bb27372e7bc93516331a15069f97
(That's essentially a "naked either monad".)
-
I disagree that the overhead of arbitrary callables is "significant." It's there, but at that point you're talking about optimizing function call counts, mostly on partials; unless you're using pipes for absolutely everything, go remove an SQL query or two and you'll get a bigger performance boost.
-
Far more languages have callable pipes. Hack is, as far as I am aware, entirely alone in having pipes be combined with a custom expression syntax rather than just using functions/callables. That isn't conclusive proof of anything, but it's certainly suggestive.
I'm going to be moving forward with this approach one way or another (if for point 1 if nothing else). I do believe it is the more flexible, more robust approach, and fits with the general strategy I recommend of small, targeted changes that combine with other small, targeted changes to offer more functionality than either of them alone. That's exactly what we're doing here.
--Larry Garfield
On Tue, Jun 8, 2021 at 4:09 PM Larry Garfield larry@garfieldtech.com
wrote:
you forgot to update one
explode(?)
tostr_split(?)
, and also, the firstfn($v) => 'strtoupper'
should be just'strtoupper'
.I deliberately made that example extra verbose to show how ugly it can
get, but I can shorten it.
Extra verbose would have been fn($v) => strtoupper($v)
, there was
obviously a typo (already correct in the second equivalent code fragment).
Anyway, I see you fixed it, and also updated the Haskell section :thumbsup:
Also, quoting from
https://wiki.php.net/rfc/first_class_callable_syntax#partial_function_application
:
"""
Both approaches to the pipe operator have their advantages. The $$ based
variant allows using more than plain function calls in each pipeline step
(e.g. you could have $$->getName() as a step, something not possible with
PFA), and is also trivially free. A PFA-based optimization would entail
significant overhead relative to simple function calls, unless special
optimization for the pipe operator usage is introduced (which may not be
possible, depending on precise semantics).
"""Could you (or Nikita) expand a bit on this (esp. the advantages of the
PFA
approach / disadvantages of Hack's approach)?It's true PFA doesn't cover every possible RHS of pipes. In practice, I
think using the piped value as an object on which to invoke a method is the
only major gap. Normally in functional code you would use a lens in that
case, which (if I am understanding those correctly; that's roughly at the
edge of my functional understanding) is essentially a function call that
wraps accessing a property or calling a method so that it feels more
functional, and thus pipes cleanly.However, piping with callables has a number of advantages.
The implementation is vastly simpler. It's simple enough that even I
can manage it, whereas Hack-style would be more considerably implementation
work.I would argue it's more flexible. Once you start thinking of
callables/functions in a first class way, producing functions on the fly
that do what you want becomes natural, and fits better with a
pipe-to-callable model. For instance, the comprehension-esque example
(which I suspect will be one of the most common use cases of pipes) is far
cleaner with a callable, as it can obviate any question about parameter
order.Another example I threw together last night is this proof of concept last
night, which works when pipes, enums, and partials are combined. I don't
think Hack-style would be capable of this, at least not as elegantly.https://gist.github.com/Crell/e484bb27372e7bc93516331a15069f97
(That's essentially a "naked either monad".)
I disagree that the overhead of arbitrary callables is "significant."
It's there, but at that point you're talking about optimizing function call
counts, mostly on partials; unless you're using pipes for absolutely
everything, go remove an SQL query or two and you'll get a bigger
performance boost.Far more languages have callable pipes. Hack is, as far as I am aware,
entirely alone in having pipes be combined with a custom expression syntax
rather than just using functions/callables. That isn't conclusive proof of
anything, but it's certainly suggestive.I'm going to be moving forward with this approach one way or another (if
for point 1 if nothing else). I do believe it is the more flexible, more
robust approach, and fits with the general strategy I recommend of small,
targeted changes that combine with other small, targeted changes to offer
more functionality than either of them alone. That's exactly what we're
doing here.
All good points IMHO.
Thanks!
--
Guilliam Xavier
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function concatenation. At the time, the main thrust of the feedback was "cool, like, but we need partial function application first so that the syntax for callables isn't so crappy."
The PFA RFC is winding down now and is looking quite good, so it's time to revisit pipes.
https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have updated it against the latest master. I also updated the RFC to use more examples that assume PFA, as the result is legit much nicer. i also tested it locally with a combined partials-and-pipes branch to make sure they play nicely together, and they do. (Yay!) Assuming PFA passes I will include those tests in the pipes branch before this one goes to a vote.
In general, much nicer with PFA than before.
A few questions though, although #1 is probably best answered by Derick Rethans:
- Will PHP consider a piped sequence a single expression? More specifically, will XDEBUG consider it a single expression, or could XDEBUG be able to set a breakpoint at each pipe assuming they are on separate lines?
I ask because if pipes were an indivisible expression from the standpoint of XDEBUG and breakpoints I would not want to see them included in PHP. Alternately if included in PHP I would avoid using them like the plague just like I avoid using fluent interfaces because of their inability to be breakpointed at each step in XDEBUG.
- Besides
throw
will there be a way to short-circuit evaluation mid-way through the pipes without having to write all of the callables to respect said short-circuiting and just return?
For example, could returning an instance of an object that implements a ShortCircuitPipeInterface
allow the pipe to short-circuit, or some other way to short-circuit and then determine after the pipe if it was short-circuited?
-Mike
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function concatenation. At the time, the main thrust of the feedback was "cool, like, but we need partial function application first so that the syntax for callables isn't so crappy."
The PFA RFC is winding down now and is looking quite good, so it's time to revisit pipes.
https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have updated it against the latest master. I also updated the RFC to use more examples that assume PFA, as the result is legit much nicer. i also tested it locally with a combined partials-and-pipes branch to make sure they play nicely together, and they do. (Yay!) Assuming PFA passes I will include those tests in the pipes branch before this one goes to a vote.
In general, much nicer with PFA than before.
A few questions though, although #1 is probably best answered by Derick Rethans:
- Will PHP consider a piped sequence a single expression? More
specifically, will XDEBUG consider it a single expression, or could
XDEBUG be able to set a breakpoint at each pipe assuming they are on
separate lines?I ask because if pipes were an indivisible expression from the
standpoint of XDEBUG and breakpoints I would not want to see them
included in PHP. Alternately if included in PHP I would avoid using
them like the plague just like I avoid using fluent interfaces because
of their inability to be breakpointed at each step in XDEBUG.
$foo |> bar(?) |> baz(?);
will produce the same AST as
baz(bar($foo));
So whatever Xdebug can do with that AST, it should still be able to do.
- Besides
throw
will there be a way to short-circuit evaluation
mid-way through the pipes without having to write all of the callables
to respect said short-circuiting and just return?For example, could returning an instance of an object that implements a
ShortCircuitPipeInterface
allow the pipe to short-circuit, or some
other way to short-circuit and then determine after the pipe if it was
short-circuited?
What you're describing is effectively monads. (There's that scary word again.) That is not covered here, although I mention it in the future scope section. There's a couple of ways it could be implemented, although you can already do so today in user-space with a method instead of a dedicated operator. The caveat is monads essentially have to be either untyped or use generics, so for now we're stuck with untyped monads.
Alternatively, you can wrap each callable in another function that wraps the short-circuiting behavior around it. That's essentially "railroad oriented programming", a term coined by Scott Wlaschin:
https://fsharpforfunandprofit.com/rop/
In other words, "I want that, but it comes later, via something more robust."
--Larry Garfield
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function concatenation. At the time, the main thrust of the feedback was "cool, like, but we need partial function application first so that the syntax for callables isn't so crappy."
The PFA RFC is winding down now and is looking quite good, so it's time to revisit pipes.
https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have updated it against the latest master. I also updated the RFC to use more examples that assume PFA, as the result is legit much nicer. i also tested it locally with a combined partials-and-pipes branch to make sure they play nicely together, and they do. (Yay!) Assuming PFA passes I will include those tests in the pipes branch before this one goes to a vote.
In general, much nicer with PFA than before.
A few questions though, although #1 is probably best answered by Derick Rethans:
- Will PHP consider a piped sequence a single expression? More
specifically, will XDEBUG consider it a single expression, or could
XDEBUG be able to set a breakpoint at each pipe assuming they are on
separate lines?I ask because if pipes were an indivisible expression from the
standpoint of XDEBUG and breakpoints I would not want to see them
included in PHP. Alternately if included in PHP I would avoid using
them like the plague just like I avoid using fluent interfaces because
of their inability to be breakpointed at each step in XDEBUG.$foo |> bar(?) |> baz(?);
will produce the same AST as
baz(bar($foo));
So whatever Xdebug can do with that AST, it should still be able to do.
That is unfortunate.
Few people write code or would write code like bazoom(baz(bar(foo($x)))) because the trailing parenthesis make it far from ergonomic. What you are proposing therefore is an ergonomic way to convert a program into a single large expression (when taken to the limit.)
Given that your pipe RFC makes practical a style of coding that was previously not practical it begs the question of addressing intermediate steps in the AST to support breakpoints, which also might require XDEBUG to introspect the values on the calling stack.
Unfortunately I do not know enough about how the internal representations work to argue that this be considered a must; hopefully Derick Rethans will comment on this.
-Mike
2021-06-07 21:00 GMT+02:00, Larry Garfield larry@garfieldtech.com:
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax for
callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time to
revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have updated
it against the latest master. I also updated the RFC to use more examples
that assume PFA, as the result is legit much nicer. i also tested it
locally with a combined partials-and-pipes branch to make sure they play
nicely together, and they do. (Yay!) Assuming PFA passes I will include
those tests in the pipes branch before this one goes to a vote.--
Larry Garfield
larry@garfieldtech.com--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi ho,
Has it been discussed the difference between the pipe operator and a
simple pipe function? Something like
function pipe() {
$args = func_get_args()
;
$result = $args[0];
$functions = array_slice($args, 1);
foreach ($functions as $function) {
$result = $function($result);
}
return $result;
}
Usage (ignoring the pesky undefined constant warnings ><):
$result = pipe(
"Hello world",
htmlentities,
str_split,
fn ($x) => array_map(strtoupper, $x),
fn ($x) => array_filter($x, fn ($v) => $v !== 'O')
);
There's also pipe operator with object, but that's obviously too
verbose compared to the operator
(https://github.com/sebastiaanluca/php-pipe-operator).
Olle
Usage (ignoring the pesky undefined constant warnings ><):
Unfortunately, you can't ignore those warnings; not least because
they're fatal errors in PHP 8, as they frankly should have been in PHP 3.
You can use our current ugly callable syntax (strings and two-element
arrays); you can tackle the complexity of unifying functions with
constants, and methods with properties (as Levi explained in the other
thread); or you can add a dedicated callable syntax, which the PFA
proposal gets us with bells on.
Regards,
--
Rowan Tommins
[IMSoP]
Usage (ignoring the pesky undefined constant warnings ><):
Unfortunately, you can't ignore those warnings; not least because
they're fatal errors in PHP 8, as they frankly should have been in PHP 3.You can use our current ugly callable syntax (strings and two-element
arrays); you can tackle the complexity of unifying functions with
constants, and methods with properties (as Levi explained in the other
thread); or you can add a dedicated callable syntax, which the PFA
proposal gets us with bells on.Regards,
I think that's a pretty good summary. There's nothing that pipes or partials do that you couldn't emulate in user-space today (really, since 5.3 is you really wanted to). The emulation is just butt-ugly and slower, which is why most people don't do it except in very specific cases or if they have a user-space library available that makes it slightly less butt-ugly.
The purpose of PFA and pipes (and short functions, and auto-capture closures, and basically everything else I've been talking about all year) is to make those things prettier and as fast as reasonable, which makes using those techniques more natural. Once you start down that path, though, there's really no usable solution before you get down as far as... PFA and Pipes in their current form.
--Larry Garfield
2021-06-28 22:12 GMT+02:00, Larry Garfield larry@garfieldtech.com:
Usage (ignoring the pesky undefined constant warnings ><):
Unfortunately, you can't ignore those warnings; not least because
they're fatal errors in PHP 8, as they frankly should have been in PHP 3.You can use our current ugly callable syntax (strings and two-element
arrays); you can tackle the complexity of unifying functions with
constants, and methods with properties (as Levi explained in the other
thread); or you can add a dedicated callable syntax, which the PFA
proposal gets us with bells on.Regards,
I think that's a pretty good summary. There's nothing that pipes or
partials do that you couldn't emulate in user-space today (really, since 5.3
is you really wanted to). The emulation is just butt-ugly and slower, which
is why most people don't do it except in very specific cases or if they have
a user-space library available that makes it slightly less butt-ugly.The purpose of PFA and pipes (and short functions, and auto-capture
closures, and basically everything else I've been talking about all year) is
to make those things prettier and as fast as reasonable, which makes using
those techniques more natural. Once you start down that path, though,
there's really no usable solution before you get down as far as... PFA and
Pipes in their current form.--Larry Garfield
The challenge is to write something that's pretty enough to be
considered idiomatic. :) The pipe operator in OCaml is defined by one
line:
let (|>) v f = f v
It wasn't always part of core, but eventually it was so common, it got
included by default. Same could happen with a pipe() function in PHP,
without the pipe operator, or that the function becomes so common, a
new keyword is added instead: pipe
. But it could probably not happen
with a Pipe object requiring you to write ->pipe() at every step -
it's too much ceremony and boilerplate.
By the way, that's alternative 5) New keyword pipe
to make the
warning about constants shut up in a certain scope. Plus some other
magic to allow nice chaining. ^^
Olle
2021-06-28 22:12 GMT+02:00, Larry Garfield larry@garfieldtech.com:
Usage (ignoring the pesky undefined constant warnings ><):
Unfortunately, you can't ignore those warnings; not least because
they're fatal errors in PHP 8, as they frankly should have been in PHP 3.You can use our current ugly callable syntax (strings and two-element
arrays); you can tackle the complexity of unifying functions with
constants, and methods with properties (as Levi explained in the other
thread); or you can add a dedicated callable syntax, which the PFA
proposal gets us with bells on.Regards,
I think that's a pretty good summary. There's nothing that pipes or
partials do that you couldn't emulate in user-space today (really, since 5.3
is you really wanted to). The emulation is just butt-ugly and slower, which
is why most people don't do it except in very specific cases or if they have
a user-space library available that makes it slightly less butt-ugly.The purpose of PFA and pipes (and short functions, and auto-capture
closures, and basically everything else I've been talking about all year) is
to make those things prettier and as fast as reasonable, which makes using
those techniques more natural. Once you start down that path, though,
there's really no usable solution before you get down as far as... PFA and
Pipes in their current form.--Larry Garfield
The challenge is to write something that's pretty enough to be
considered idiomatic. :) The pipe operator in OCaml is defined by one
line:let (|>) v f = f v
It wasn't always part of core, but eventually it was so common, it got
included by default. Same could happen with a pipe() function in PHP,
without the pipe operator, or that the function becomes so common, a
new keyword is added instead:pipe
. But it could probably not happen
with a Pipe object requiring you to write ->pipe() at every step -
it's too much ceremony and boilerplate.By the way, that's alternative 5) New keyword
pipe
to make the
warning about constants shut up in a certain scope. Plus some other
magic to allow nice chaining. ^^Olle
"Idiomatic PHP" consists primarily of associative arrays, used in ways no sane person would ever use a dictionary, but the code is in a method so it gets called OOP even though it's barely procedural.
That's not an idiom I have any interest in supporting, and have in fact made a career out of training people out of. :-)
There are already libraries that let you write ->pipe(). The PHP League has one, for instance:
https://github.com/thephpleague/pipeline
I've seen others, but they're no less ugly and offer no better migration path into a core syntax. PHP is just not designed as a user-extensible language. (cf, "Growing a Language" by Guy Steele, one of the best presentations ever given: https://www.youtube.com/watch?v=_ahvzDzKdB0)
Also of note, the OCaml definition there is almost exactly the same as the current patch; there's a request out I'm working on now to change the implementation to ensure that the LHS is fully evaluated before the RHS, but it's interesting to see that OCaml's version does have the out-of-order challenge. (Although in a functional language it's semantically a meaningless difference, by design.)
Overall, I really don't like the idea of special-casing pipes to change what symbol table gets looked up. That's just asking for edge cases to bite us later, especially when the root problem isn't with pipes in the first place; it's with PHP lacking either a function-reference syntax or PFA (which gives us a function-reference syntax for free). Fix the real problem, don't hack around it in what should be a very simple feature.
--Larry Garfield
2021-06-28 23:36 GMT+02:00, Larry Garfield larry@garfieldtech.com:
2021-06-28 22:12 GMT+02:00, Larry Garfield larry@garfieldtech.com:
Usage (ignoring the pesky undefined constant warnings ><):
Unfortunately, you can't ignore those warnings; not least because
they're fatal errors in PHP 8, as they frankly should have been in PHP
3.You can use our current ugly callable syntax (strings and two-element
arrays); you can tackle the complexity of unifying functions with
constants, and methods with properties (as Levi explained in the other
thread); or you can add a dedicated callable syntax, which the PFA
proposal gets us with bells on.Regards,
I think that's a pretty good summary. There's nothing that pipes or
partials do that you couldn't emulate in user-space today (really, since
5.3
is you really wanted to). The emulation is just butt-ugly and slower,
which
is why most people don't do it except in very specific cases or if they
have
a user-space library available that makes it slightly less butt-ugly.The purpose of PFA and pipes (and short functions, and auto-capture
closures, and basically everything else I've been talking about all
year) is
to make those things prettier and as fast as reasonable, which makes
using
those techniques more natural. Once you start down that path, though,
there's really no usable solution before you get down as far as... PFA
and
Pipes in their current form.--Larry Garfield
The challenge is to write something that's pretty enough to be
considered idiomatic. :) The pipe operator in OCaml is defined by one
line:let (|>) v f = f v
It wasn't always part of core, but eventually it was so common, it got
included by default. Same could happen with a pipe() function in PHP,
without the pipe operator, or that the function becomes so common, a
new keyword is added instead:pipe
. But it could probably not happen
with a Pipe object requiring you to write ->pipe() at every step -
it's too much ceremony and boilerplate.By the way, that's alternative 5) New keyword
pipe
to make the
warning about constants shut up in a certain scope. Plus some other
magic to allow nice chaining. ^^Olle
"Idiomatic PHP" consists primarily of associative arrays, used in ways no
sane person would ever use a dictionary, but the code is in a method so it
gets called OOP even though it's barely procedural.That's not an idiom I have any interest in supporting, and have in fact made
a career out of training people out of. :-)There are already libraries that let you write ->pipe(). The PHP League
has one, for instance:https://github.com/thephpleague/pipeline
I've seen others, but they're no less ugly and offer no better migration
path into a core syntax. PHP is just not designed as a user-extensible
language. (cf, "Growing a Language" by Guy Steele, one of the best
presentations ever given: https://www.youtube.com/watch?v=_ahvzDzKdB0)Also of note, the OCaml definition there is almost exactly the same as the
current patch; there's a request out I'm working on now to change the
implementation to ensure that the LHS is fully evaluated before the RHS, but
it's interesting to see that OCaml's version does have the out-of-order
challenge. (Although in a functional language it's semantically a
meaningless difference, by design.)Overall, I really don't like the idea of special-casing pipes to change what
symbol table gets looked up. That's just asking for edge cases to bite us
later, especially when the root problem isn't with pipes in the first place;
it's with PHP lacking either a function-reference syntax or PFA (which gives
us a function-reference syntax for free). Fix the real problem, don't hack
around it in what should be a very simple feature.--Larry Garfield
Mm. Assoc arrays are by now known to be not so good. I hope...
OCaml is strictly evaluated, not lazy like Haskell. So the order might
matter, dunno, I don't use this operator often. :) My point was mostly
that it's very easy to add in OCaml - just one line. And as in
Haskell, you can define operators in your modules. Similarly, in PHP
it's easy to do super-dynamic stuff like "new $someclass", which is
not remotely possible in FP (good or bad, depending on your religion).
Adding a new pipe keyword is like the list() keyword, kind of. A bad
idea, haha. But I think all stones can be turned, if this RFC now gets
a no. :/
Would a slimmed down version have more support? How about removing the
variadic operator, and let the user manually add the lambda for those
cases? Could reduce the complexity while still covering maybe 80% of
the use-cases? Same with removing support for named arguments. So '?'
would only be a short-cut to get rid of boilerplate like $strlen = fn($x) => strlen($x)
.
Overall, I really don't like the idea of special-casing pipes to change what
symbol table gets looked up.
Still wondering if this could be a per-file or per-library setting
somehow, to opt-in into pipe behaviour when so desired. Or rather, to
opt-in into this or that behaviour needed to do more idiomatic pipe.
Here's one boilerplaty pipe:
// Original snippet with nested calls and hard-to-follow program flow
$result = array_filter(
array_map(
'strtoupper',
str_split(
htmlentities("Hello World")
)
),
fn($v) => $v !== 'O'
);
// Boilerplate setup
$htmlentities = fn($x) => htmlentities($x);
$str_split = fn($x) => str_split($x);
$strtoupper = fn($x) => strtoupper($x);
// Actual calculation
$result = pipe(
"Hello world",
$htmlentities,
$str_split,
fn ($x) => array_map($strtoupper, $x),
fn ($x) => array_filter($x, fn ($v) => $v !== 'O')
);
Where pipe() is just:
function pipe() {
$args = func_get_args()
;
$result = $args[0];
$functions = array_slice($args, 1);
foreach ($functions as $function) {
$result = $function($result);
}
return $result;
}
Olle
Mm. Assoc arrays are by now known to be not so good. I hope...
There are millions of PHP sites build on anonymous arrays today.
OCaml is strictly evaluated, not lazy like Haskell. So the order might
matter, dunno, I don't use this operator often. :) My point was mostly
that it's very easy to add in OCaml - just one line. And as in
Haskell, you can define operators in your modules. Similarly, in PHP
it's easy to do super-dynamic stuff like "new $someclass", which is
not remotely possible in FP (good or bad, depending on your religion).Adding a new pipe keyword is like the list() keyword, kind of. A bad
idea, haha. But I think all stones can be turned, if this RFC now gets
a no. :/Would a slimmed down version have more support? How about removing the
variadic operator, and let the user manually add the lambda for those
cases? Could reduce the complexity while still covering maybe 80% of
the use-cases? Same with removing support for named arguments. So '?'
would only be a short-cut to get rid of boilerplate like$strlen = fn($x) => strlen($x)
.
I talked with Joe about this, and the answer is no. Most of the complexity comes from the initial "this is a function call, oops no, it's a partial call so we switch to doing that instead", which ends up interacting with the engine in a lot of different places. Once you've done that, supporting one placeholder or multiple, variadics or not, etc. is only a small incremental increase in complexity.
Overall, I really don't like the idea of special-casing pipes to change what
symbol table gets looked up.Still wondering if this could be a per-file or per-library setting
somehow, to opt-in into pipe behaviour when so desired. Or rather, to
opt-in into this or that behaviour needed to do more idiomatic pipe.Here's one boilerplaty pipe:
snip
We're in the pipe thread here, not PFA. :-) And really, you're solving the wrong problem. Pipes are trivial. They're only clunky because of PHP's lack of decent callable syntax. PFA gives us that, but the engine makes the implementation more complex than it seems like at first glance.
Trying to come up with complex workarounds to make pipes pretty without helping anything else is a fool's errand, especially when we have a working PFA RFC that's about to end voting. (And right now is losing by a very slim margin, but could pass if a few people change their minds.)
Aside from something like Nikita's ...-only function reference RFC, which only handles half the problem (it doesn't do anything to make multi-arg functions work with pipes at all), any other solution is going to end up reinventing PFA one way or another, or reinventing existing ugly user-space libraries. one way or another
I've not yet decided if I'm going to bring pipes to a vote if PFA doesn't pass. I'm tempted to, but it would require rewriting all the RFC text back to the uglier version without PFA, and yeah, it's not going to look as pretty. And the main pushback a year ago when I first brought it up was "PFA first, please, so the callable syntax isn't ugly." And... here we are.
--Larry Garfield
I talked with Joe about this, and the answer is no. Most of the complexity
comes from the initial "this is a function call, oops no, it's a partial
call so we switch to doing that instead", which ends up interacting with the
engine in a lot of different places. Once you've done that, supporting one
placeholder or multiple, variadics or not, etc. is only a small incremental
increase in complexity.
Hm, I was thinking more about the conceptual complexity, not the
implementation, but seems like the argument "cover all expected
use-cases" was used too. :) So no half-measures...
Thanks for your feedback.
Olle
Overall, I really don't like the idea of special-casing pipes to change
what
symbol table gets looked up.Still wondering if this could be a per-file or per-library setting
somehow, to opt-in into pipe behaviour when so desired. Or rather, to
opt-in into this or that behaviour needed to do more idiomatic pipe.Here's one boilerplaty pipe:
snip
We're in the pipe thread here, not PFA. :-) And really, you're solving the
wrong problem. Pipes are trivial. They're only clunky because of PHP's
lack of decent callable syntax. PFA gives us that, but the engine makes the
implementation more complex than it seems like at first glance.Trying to come up with complex workarounds to make pipes pretty without
helping anything else is a fool's errand, especially when we have a working
PFA RFC that's about to end voting. (And right now is losing by a very slim
margin, but could pass if a few people change their minds.)Aside from something like Nikita's ...-only function reference RFC, which
only handles half the problem (it doesn't do anything to make multi-arg
functions work with pipes at all), any other solution is going to end up
reinventing PFA one way or another, or reinventing existing ugly user-space
libraries. one way or anotherI've not yet decided if I'm going to bring pipes to a vote if PFA doesn't
pass. I'm tempted to, but it would require rewriting all the RFC text back
to the uglier version without PFA, and yeah, it's not going to look as
pretty. And the main pushback a year ago when I first brought it up was
"PFA first, please, so the callable syntax isn't ugly." And... here we
are.--Larry Garfield
2021-06-29 0:54 GMT+02:00, Larry Garfield larry@garfieldtech.com:
Mm. Assoc arrays are by now known to be not so good. I hope...
There are millions of PHP sites build on anonymous arrays today.
OCaml is strictly evaluated, not lazy like Haskell. So the order might
matter, dunno, I don't use this operator often. :) My point was mostly
that it's very easy to add in OCaml - just one line. And as in
Haskell, you can define operators in your modules. Similarly, in PHP
it's easy to do super-dynamic stuff like "new $someclass", which is
not remotely possible in FP (good or bad, depending on your religion).Adding a new pipe keyword is like the list() keyword, kind of. A bad
idea, haha. But I think all stones can be turned, if this RFC now gets
a no. :/Would a slimmed down version have more support? How about removing the
variadic operator, and let the user manually add the lambda for those
cases? Could reduce the complexity while still covering maybe 80% of
the use-cases? Same with removing support for named arguments. So '?'
would only be a short-cut to get rid of boilerplate like$strlen = fn($x) => strlen($x)
.I talked with Joe about this, and the answer is no. Most of the complexity
comes from the initial "this is a function call, oops no, it's a partial
call so we switch to doing that instead", which ends up interacting with the
engine in a lot of different places. Once you've done that, supporting one
placeholder or multiple, variadics or not, etc. is only a small incremental
increase in complexity.Overall, I really don't like the idea of special-casing pipes to change
what
symbol table gets looked up.Still wondering if this could be a per-file or per-library setting
somehow, to opt-in into pipe behaviour when so desired. Or rather, to
opt-in into this or that behaviour needed to do more idiomatic pipe.Here's one boilerplaty pipe:
snip
We're in the pipe thread here, not PFA. :-) And really, you're solving the
wrong problem. Pipes are trivial. They're only clunky because of PHP's
lack of decent callable syntax. PFA gives us that, but the engine makes the
implementation more complex than it seems like at first glance.Trying to come up with complex workarounds to make pipes pretty without
helping anything else is a fool's errand, especially when we have a working
PFA RFC that's about to end voting. (And right now is losing by a very slim
margin, but could pass if a few people change their minds.)Aside from something like Nikita's ...-only function reference RFC, which
only handles half the problem (it doesn't do anything to make multi-arg
functions work with pipes at all), any other solution is going to end up
reinventing PFA one way or another, or reinventing existing ugly user-space
libraries. one way or anotherI've not yet decided if I'm going to bring pipes to a vote if PFA doesn't
pass. I'm tempted to, but it would require rewriting all the RFC text back
to the uglier version without PFA, and yeah, it's not going to look as
pretty. And the main pushback a year ago when I first brought it up was
"PFA first, please, so the callable syntax isn't ugly." And... here we
are.--Larry Garfield
Is there no "pre-vote" process for RFCs? For example, letting the
voting members rate different alternatives, in a ranking fashion, to
see which one is most and least popular. Feels like a lot of work is
getting wasted if something is voted down on a small margin.
Olle
2021-06-28 22:04 GMT+02:00, Rowan Tommins rowan.collins@gmail.com:
Usage (ignoring the pesky undefined constant warnings ><):
Unfortunately, you can't ignore those warnings; not least because
they're fatal errors in PHP 8, as they frankly should have been in PHP 3.You can use our current ugly callable syntax (strings and two-element
arrays); you can tackle the complexity of unifying functions with
constants, and methods with properties (as Levi explained in the other
thread); or you can add a dedicated callable syntax, which the PFA
proposal gets us with bells on.
Sorry for hijacking the thread, but are there no other alternatives,
really? Just brainstorming:
-
Setting to silence the warning. Probably frowned upon, AND requires
that functions/methods are case sensitive, which they are not right
now. BUT, constants are always case sensitive since 7.3, so the risk
of collision is not that high...? Assuming constants are by convention
always UPPER_CASE, and functions either snake_case or camelCase. You
can argue that the setting together with a CI to check cases would be
reasonably safe. -
Setting to silence the warning IF and only if argument expects a
callable, like in array_map (won't work with a pipe() function,
though, since pipe() would take any number of arguments and that can't
be typed) -
Silence the warning if you type-case explicitly, like in
pipe($start, (callable) htmlentities);
. Another alternative is
(fn)
as a type-cast. Not much better thanpipe($start, htmlentities(?))
, I guess. Just different style. -
Silence the warning ONLY when it's the right-hand argument to pipe
operator, like$start |> str_len
.
All stupid?
Sorry for hijacking the thread, but are there no other alternatives,
really? Just brainstorming:
- Setting to silence the warning.
Just to reiterate: in PHP 8.0, an undefined constant is not a warning,
it's an error. My apologies to code golfers: you can no longer save two
bytes by leaving the quote marks off your strings.
However, that's not really the problem. The problem is when there is a
constant with that name:
const foo='strtoupper';
function foo($x) { return 'test'; }
$input = ['hello', 'world'];
var_dump( array_map(foo, $input) ); // this runs strtoupper()
, not foo()
This doesn't work even in old versions of PHP where undefined constants
fell back to strings.
Even in cases where this trick did work in older versions of PHP, it was
just a variant of option one, "use our current ugly callable syntax" -
it saved you those two bytes, but it didn't actually provide you a
function reference.
Unifying the constant and function name tables would not be to just a
different way of writing strings, it would let array_map(foo, $input)
actually check that function foo existed, and represent callables as a
proper type. Meanwhile, to let array_map($object->foo, $input) do the
same thing (instead of the current [$object, 'foo'] syntax) you also
need to unify the method and property tables, which is probably even harder.
- Setting to silence the warning IF and only if argument expects a
callable, like in array_map (won't work with a pipe() function,
though, since pipe() would take any number of arguments and that can't
be typed)
In the general case, this is a non-starter: the parameters need to be
parsed from the source code before function definitions are even known.
You could special-case a handful of built-in functions, but that would
be extremely clunky.
- Silence the warning if you type-case explicitly, like in
pipe($start, (callable) htmlentities);
. Another alternative is
(fn)
as a type-cast. Not much better thanpipe($start, htmlentities(?))
, I guess. Just different style.
This falls into my third option: "add a dedicated callable syntax". That
could be something that looks a bit like PFA but isn't, like Nikita's
RFC; or something that looks a bit like a type cast; or any number of
other ideas which have been brainstormed for about as long as I've been
programming PHP.
- Silence the warning ONLY when it's the right-hand argument to pipe
operator, like$start |> str_len
.
Re-wording this as "interpret the unquoted word as a function reference
rather than a constant when...", this one is at least plausible. In
practice, though, a lot of functions don't take only one parameter, so
the previous pipe proposal included a placeholder for which argument you
wanted to "pipe into". At which point you don't need to special case
keywords, because you can just write this:
$start |> str_len($$)
Regards,
--
Rowan Tommins
[IMSoP]
2021-06-29 0:06 GMT+02:00, Rowan Tommins rowan.collins@gmail.com:
Sorry for hijacking the thread, but are there no other alternatives,
really? Just brainstorming:
- Setting to silence the warning.
Just to reiterate: in PHP 8.0, an undefined constant is not a warning,
it's an error. My apologies to code golfers: you can no longer save two
bytes by leaving the quote marks off your strings.However, that's not really the problem. The problem is when there is a
constant with that name:const foo='strtoupper';
function foo($x) { return 'test'; }
$input = ['hello', 'world'];
var_dump( array_map(foo, $input) ); // this runsstrtoupper()
, not foo()This doesn't work even in old versions of PHP where undefined constants
fell back to strings.Even in cases where this trick did work in older versions of PHP, it was
just a variant of option one, "use our current ugly callable syntax" -
it saved you those two bytes, but it didn't actually provide you a
function reference.Unifying the constant and function name tables would not be to just a
different way of writing strings, it would let array_map(foo, $input)
actually check that function foo existed, and represent callables as a
proper type. Meanwhile, to let array_map($object->foo, $input) do the
same thing (instead of the current [$object, 'foo'] syntax) you also
need to unify the method and property tables, which is probably even
harder.
- Setting to silence the warning IF and only if argument expects a
callable, like in array_map (won't work with a pipe() function,
though, since pipe() would take any number of arguments and that can't
be typed)In the general case, this is a non-starter: the parameters need to be
parsed from the source code before function definitions are even known.
You could special-case a handful of built-in functions, but that would
be extremely clunky.
- Silence the warning if you type-case explicitly, like in
pipe($start, (callable) htmlentities);
. Another alternative is
(fn)
as a type-cast. Not much better thanpipe($start, htmlentities(?))
, I guess. Just different style.This falls into my third option: "add a dedicated callable syntax". That
could be something that looks a bit like PFA but isn't, like Nikita's
RFC; or something that looks a bit like a type cast; or any number of
other ideas which have been brainstormed for about as long as I've been
programming PHP.
- Silence the warning ONLY when it's the right-hand argument to pipe
operator, like$start |> str_len
.Re-wording this as "interpret the unquoted word as a function reference
rather than a constant when...", this one is at least plausible. In
practice, though, a lot of functions don't take only one parameter, so
the previous pipe proposal included a placeholder for which argument you
wanted to "pipe into". At which point you don't need to special case
keywords, because you can just write this:$start |> str_len($$)
True. I wish we had numbers for how common the case is when you DON'T
want to pipe into the first argument. If it's rare enough, it might be
worth it to let the rare cases be dealt with by writing manual
lambdas. So allow some boilerplate. Another alternative would be to
add both '?' and parsing unquoted string as function reference
together with pipe operator, but start with the simple one (whichever
that is, I wouldn't know). Or start with the one that has chance of
being accepted by the voters. :)
Regards,
--
Rowan Tommins
[IMSoP]
Thanks for your explanations!
Olle
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax
for callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time
to revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use
more examples that assume PFA, as the result is legit much nicer. i
also tested it locally with a combined partials-and-pipes branch to
make sure they play nicely together, and they do. (Yay!) Assuming PFA
passes I will include those tests in the pipes branch before this one
goes to a vote.
Hi again.
With PFA being declined, I've again reworked the Pipes RFC.
-
It now does not use PFA in any examples, but it does use Nikita's first-class-callables RFC that looks like it's going to pass easily.
-
With major hand-holding from Levi Morrison and Joe Watkins, the implementation has shifted a bit. It now evaluates left-to-right, always, whereas the previous version evaluated right-to-left. That is, instead of $a |> $b |> $c desugaring into $c($b($a)), it now becomes effectively $tmp = $a; $tmp = $b($tmp); $tmp = $c($tmp); That matters if $b or $c are function calls that return a callable, as they are then only called when the pipeline gets to that part of the expression. (If all the functions involved are pure functions, then it doesn't make a difference in practice.)
-
I included references to several existing PHP libraries that implement similar logic, in mostly complex and ugly ways.
-
Of note, Brent posted a Twitter poll last week about pipes, and the response was overwhelmingly in favor. (https://twitter.com/brendt_gd/status/1408271132650885123) Naturally a Twitter poll is extremely unscientific, but I think between the existing libraries and the response there the answer to the question "is there actually a demand for this feature?" is unquestionably yes.
-
Examples have been reworked to be a bit prettier.
-
Added another language reference that has a pipe operator that works basically like described here. (OCaml)
I am planning to take this version of the RFC to a vote on Monday or Tuesday, as Tuesday is the last day possible to start a vote for 8.1 features.
--Larry Garfield
2021-07-04 4:12 GMT+02:00, Larry Garfield larry@garfieldtech.com:
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax
for callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time
to revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use
more examples that assume PFA, as the result is legit much nicer. i
also tested it locally with a combined partials-and-pipes branch to
make sure they play nicely together, and they do. (Yay!) Assuming PFA
passes I will include those tests in the pipes branch before this one
goes to a vote.Hi again.
With PFA being declined, I've again reworked the Pipes RFC.
It now does not use PFA in any examples, but it does use Nikita's
first-class-callables RFC that looks like it's going to pass easily.With major hand-holding from Levi Morrison and Joe Watkins, the
implementation has shifted a bit. It now evaluates left-to-right, always,
whereas the previous version evaluated right-to-left. That is, instead of
$a |> $b |> $c desugaring into $c($b($a)), it now becomes effectively $tmp =
$a; $tmp = $b($tmp); $tmp = $c($tmp); That matters if $b or $c are function
calls that return a callable, as they are then only called when the pipeline
gets to that part of the expression.
Hi! Can you flesh out an example for this, please? Not sure I get the
use-case where it matters. Couldn't find any example inside the PR
either (the tests) that show-cased this particular implementation
detail. Did I miss it?
Olle
2021-07-04 4:12 GMT+02:00, Larry Garfield larry@garfieldtech.com:
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax
for callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time
to revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use
more examples that assume PFA, as the result is legit much nicer. i
also tested it locally with a combined partials-and-pipes branch to
make sure they play nicely together, and they do. (Yay!) Assuming PFA
passes I will include those tests in the pipes branch before this one
goes to a vote.Hi again.
With PFA being declined, I've again reworked the Pipes RFC.
It now does not use PFA in any examples, but it does use Nikita's
first-class-callables RFC that looks like it's going to pass easily.With major hand-holding from Levi Morrison and Joe Watkins, the
implementation has shifted a bit. It now evaluates left-to-right, always,
whereas the previous version evaluated right-to-left. That is, instead of
$a |> $b |> $c desugaring into $c($b($a)), it now becomes effectively $tmp =
$a; $tmp = $b($tmp); $tmp = $c($tmp); That matters if $b or $c are function
calls that return a callable, as they are then only called when the pipeline
gets to that part of the expression.Hi! Can you flesh out an example for this, please? Not sure I get the
use-case where it matters. Couldn't find any example inside the PR
either (the tests) that show-cased this particular implementation
detail. Did I miss it?
The "evaluation order" test is for exactly that:
With the old desugaring way, _test2() was called first before anything else. With the new way, it's called after _test1(), as most people would expect from reading it.
--Larry Garfield
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax
for callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time
to revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use
more examples that assume PFA, as the result is legit much nicer. i
also tested it locally with a combined partials-and-pipes branch to
make sure they play nicely together, and they do. (Yay!) Assuming PFA
passes I will include those tests in the pipes branch before this one
goes to a vote.Hi again.
With PFA being declined, I've again reworked the Pipes RFC.
It now does not use PFA in any examples, but it does use Nikita's
first-class-callables RFC that looks like it's going to pass easily.With major hand-holding from Levi Morrison and Joe Watkins, the
implementation has shifted a bit. It now evaluates left-to-right,
always, whereas the previous version evaluated right-to-left. That is,
instead of $a |> $b |> $c desugaring into $c($b($a)), it now becomes
effectively $tmp = $a; $tmp = $b($tmp); $tmp = $c($tmp); That matters
if $b or $c are function calls that return a callable, as they are then
only called when the pipeline gets to that part of the expression. (If
all the functions involved are pure functions, then it doesn't make a
difference in practice.)I included references to several existing PHP libraries that
implement similar logic, in mostly complex and ugly ways.Of note, Brent posted a Twitter poll last week about pipes, and the
response was overwhelmingly in favor.
(https://twitter.com/brendt_gd/status/1408271132650885123) Naturally a
Twitter poll is extremely unscientific, but I think between the
existing libraries and the response there the answer to the question
"is there actually a demand for this feature?" is unquestionably yes.Examples have been reworked to be a bit prettier.
Added another language reference that has a pipe operator that works
basically like described here. (OCaml)I am planning to take this version of the RFC to a vote on Monday or
Tuesday, as Tuesday is the last day possible to start a vote for 8.1
features.--Larry Garfield
Based on feedback on the PR, I've updated the RFC to forbid functions that pass or return by reference. They're not really useful in pipes at all, and were only supported before because the implementation happened to allow it.
The PR hasn't been updated for that yet, but I figure that's easy enough to update post-vote if it passes.
--Larry Garfield
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was "cool,
like, but we need partial function application first so that the syntax
for callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's time
to revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use
more examples that assume PFA, as the result is legit much nicer. i
also tested it locally with a combined partials-and-pipes branch to
make sure they play nicely together, and they do. (Yay!) Assuming PFA
passes I will include those tests in the pipes branch before this one
goes to a vote.Hi again.
With PFA being declined, I've again reworked the Pipes RFC.
It now does not use PFA in any examples, but it does use Nikita's
first-class-callables RFC that looks like it's going to pass easily.With major hand-holding from Levi Morrison and Joe Watkins, the
implementation has shifted a bit. It now evaluates left-to-right,
always, whereas the previous version evaluated right-to-left. That is,
instead of $a |> $b |> $c desugaring into $c($b($a)), it now becomes
effectively $tmp = $a; $tmp = $b($tmp); $tmp = $c($tmp); That matters
if $b or $c are function calls that return a callable, as they are then
only called when the pipeline gets to that part of the expression. (If
all the functions involved are pure functions, then it doesn't make a
difference in practice.)I included references to several existing PHP libraries that
implement similar logic, in mostly complex and ugly ways.Of note, Brent posted a Twitter poll last week about pipes, and the
response was overwhelmingly in favor.
(https://twitter.com/brendt_gd/status/1408271132650885123) Naturally a
Twitter poll is extremely unscientific, but I think between the
existing libraries and the response there the answer to the question
"is there actually a demand for this feature?" is unquestionably yes.Examples have been reworked to be a bit prettier.
Added another language reference that has a pipe operator that works
basically like described here. (OCaml)I am planning to take this version of the RFC to a vote on Monday or
Tuesday, as Tuesday is the last day possible to start a vote for 8.1
features.--Larry Garfield
Based on feedback on the PR, I've updated the RFC to forbid functions
that pass or return by reference. They're not really useful in pipes
at all, and were only supported before because the implementation
happened to allow it.The PR hasn't been updated for that yet, but I figure that's easy
enough to update post-vote if it passes.
Sorry for the noise, but after some discussion with Joe it looks like blocking references in pipes is actually much harder than it sounded like, and would require a completely opcode based implementation rather than the completely AST-based implementation. References on pipes are not really useful but in practice they don't hurt anything. I've instead added more tests to validate that they behave "as expected" and noted that in the RFC instead.
--Larry Garfield
Just to clarify,
I said it didn't look like it could be a pure AST implementation, and that
it looks like you may need one additional instruction.
It does look that way to me - if only to throw a sensible error
specifically for pipes but also because it makes the imposition of specific
behaviour for pipes a little easier, but it doesn't make it a super
complicated thing.
I also said I didn't know what the right answer was with regard to refs. I
still don't, although I lean towards blocking them at the moment having
spent a little more time looking at it.
I don't really think we've had long enough to have this conversation
properly.
Cheers
Joe
Hi folks. Me again.
A year ago, I posted an RFC for a pipe operator, |>, aka function
concatenation. At the time, the main thrust of the feedback was
"cool,
like, but we need partial function application first so that the
syntax
for callables isn't so crappy."The PFA RFC is winding down now and is looking quite good, so it's
time
to revisit pipes.https://wiki.php.net/rfc/pipe-operator-v2
Nothing radical has changed in the proposal since last year. I have
updated it against the latest master. I also updated the RFC to use
more examples that assume PFA, as the result is legit much nicer. i
also tested it locally with a combined partials-and-pipes branch to
make sure they play nicely together, and they do. (Yay!) Assuming
PFA
passes I will include those tests in the pipes branch before this
one
goes to a vote.Hi again.
With PFA being declined, I've again reworked the Pipes RFC.
It now does not use PFA in any examples, but it does use Nikita's
first-class-callables RFC that looks like it's going to pass easily.With major hand-holding from Levi Morrison and Joe Watkins, the
implementation has shifted a bit. It now evaluates left-to-right,
always, whereas the previous version evaluated right-to-left. That
is,
instead of $a |> $b |> $c desugaring into $c($b($a)), it now becomes
effectively $tmp = $a; $tmp = $b($tmp); $tmp = $c($tmp); That matters
if $b or $c are function calls that return a callable, as they are
then
only called when the pipeline gets to that part of the expression.
(If
all the functions involved are pure functions, then it doesn't make a
difference in practice.)I included references to several existing PHP libraries that
implement similar logic, in mostly complex and ugly ways.Of note, Brent posted a Twitter poll last week about pipes, and the
response was overwhelmingly in favor.
(https://twitter.com/brendt_gd/status/1408271132650885123) Naturally
a
Twitter poll is extremely unscientific, but I think between the
existing libraries and the response there the answer to the question
"is there actually a demand for this feature?" is unquestionably yes.Examples have been reworked to be a bit prettier.
Added another language reference that has a pipe operator that
works
basically like described here. (OCaml)I am planning to take this version of the RFC to a vote on Monday or
Tuesday, as Tuesday is the last day possible to start a vote for 8.1
features.--Larry Garfield
Based on feedback on the PR, I've updated the RFC to forbid functions
that pass or return by reference. They're not really useful in pipes
at all, and were only supported before because the implementation
happened to allow it.The PR hasn't been updated for that yet, but I figure that's easy
enough to update post-vote if it passes.Sorry for the noise, but after some discussion with Joe it looks like
blocking references in pipes is actually much harder than it sounded like,
and would require a completely opcode based implementation rather than the
completely AST-based implementation. References on pipes are not really
useful but in practice they don't hurt anything. I've instead added more
tests to validate that they behave "as expected" and noted that in the RFC
instead.--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php