Pipe Operator v2

php.internals

Sara Golemon

10 years ago
With the branching of 7.1, and after some reflection on the previous feedback, I'd like to reopen discussion of the Pipe Operator RFC https://wiki.php.net/rfc/pipe-operator which I had previously put on hold. I've changed much of the argument wording of the proposal, but not the substantive feature set. If you still feel it's unworkable, I'd like to encourage you to respond with what you think would make it workable (if anything). Thanks. -Sara

Unnamed Person

10 years ago
to me this code is perfectly readable and static code analysis is only complaining about missing semicolons at the end of the lines and short variable names: $x = loadConfig(); $x = buildDic($x); $x = getApp($x) $x = getRouter($x) $x = getDispatcher($x, $request) $x = dispatchBusinessLogic($x, $request, new Response()) $x = renderResponse($x) $x = buildPsr7Response($x) $response =emit($x); I'm not sure if there is a ORM or database library out there which constructs SQL queries with non-oop calls, maybe you can give a real-world example. Regards Thomas Sara Golemon wrote on 21.07.2016 01:42:

Yasuo Ohgaki

10 years ago
Hi Thomas, On Thu, Jul 21, 2016 at 9:05 AM, Thomas Bley <mails@thomasbley.de> wrote:
> to me this code is perfectly readable and static code analysis is only complaining about missing semicolons at the end of the lines and short variable names: > > $x = loadConfig(); > $x = buildDic($x); > $x = getApp($x) > $x = getRouter($x) > $x = getDispatcher($x, $request) > $x = dispatchBusinessLogic($x, $request, new Response()) > $x = renderResponse($x) > $x = buildPsr7Response($x) > $response =emit($x); >
I agree the example code is readable, but it makes me feel the language is a little obsolete. Many coding standards, if not most, require to have meaningful variable names even for temp variables. $response = loadConfig() |> buildDic($$) |> getApp($$) |> getRouter($$) |> getDispatcher($$, $request) |> dispatchBusinessLogic($$, $request, new Response()) |> renderResponse($$) |> buildPsr7Response($$) |> emit($$); Nice, clean, readable and explicit. i.e. Don't have convert $x is return value from previous call in programmer's head.
> I'm not sure if there is a ORM or database library out there which constructs SQL queries with non-oop calls, maybe you can give a real-world example.
F# supports function pipelining by |> operator https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/functions-%5bfsharp%5d#function-composition-and-pipelining It differs a little, but real world function pipelining examples could be found in F#/OCaml codes. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Sara Golemon

10 years ago
> On Thu, Jul 21, 2016 at 9:05 AM, Thomas Bley <mails@thomasbley.de> wrote: > to me this code is perfectly readable and static code analysis is only complaining about missing semicolons at the end of the lines and short variable names: > > $x = loadConfig(); > $x = buildDic($x); > $x = getApp($x) > $x = getRouter($x) > $x = getDispatcher($x, $request) > $x = dispatchBusinessLogic($x, $request, new Response()) > $x = renderResponse($x) > $x = buildPsr7Response($x) > $response =emit($x); >
A proper static analyzer would also not that $x is continuously changing types, another heave code smell.
> I'm not sure if there is a ORM or database library out there which constructs > SQL queries with non-oop calls, maybe you can give a real-world example. >
The third example in the RFC (FBShipIt) shows this exact operator in a real-world usage in "php-like" code. -Sara

Stas Malyshev

10 years ago
Hi!
>> $x = loadConfig(); >> $x = buildDic($x); >> $x = getApp($x) >> $x = getRouter($x) >> $x = getDispatcher($x, $request) >> $x = dispatchBusinessLogic($x, $request, new Response()) >> $x = renderResponse($x) >> $x = buildPsr7Response($x) >> $response =emit($x); >> > > I agree the example code is readable, but it makes me feel the > language is a little obsolete.
This is a mindset that I feel to be objectionable and take issue with. The idea that we have to constantly invent new syntax to replace working old one, just because old is somehow "obsolete", even though new syntax's only advantage is doing things slightly differently - it seems to me an exactly wrong idea. It may be exciting to invent new syntaxes - but for an industry programmer that has other priorities, like code stability, compatibility, maintainability, etc. "new" is not a positive things unless it gives them measurable or at least perceivable improvement on these qualities. Existing syntax is not "obsolete" and works completely well. New syntax invents new magic variables (thing that never existed in PHP before, adding a whole new conceptual level to PHP mental model) and a new way of doing the same thing that is already perfectly doable right now with exactly the same effort. I personally strongly object to such changes. There is a lot of ways in which PHP needs improvement, but right now I think inventing more syntax tricks in not one of them. Even in syntax department, PHP has areas where we could use improvement (e.g. to name named arguments as one) but this one doesn't seem to do much but doing the same thing in a shiny new way. Read: less comprehensible for people not watching "latest new 20 syntaxes PHP invented in the next version", more things to learn to read PHP code, more things to maintain, more complexity for the language that once was supposed to be accessible to beginners. This is the price of all innovation, but sometimes benefits are much greater and the price is completely warranted. I do not feel this is the case here.
-- Stas Malyshev smalyshev@gmail.com

Sara Golemon

10 years ago
On Sat, Jul 23, 2016 at 1:11 PM, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> There is a lot of ways in which PHP needs improvement, but right now I > think inventing more syntax tricks in not one of them. Even in syntax > department, PHP has areas where we could use improvement (e.g. to name > named arguments as one) but this one doesn't seem to do much but doing > the same thing in a shiny new way. Read: less comprehensible for people > not watching "latest new 20 syntaxes PHP invented in the next version", > more things to learn to read PHP code, more things to maintain, more > complexity for the language that once was supposed to be accessible to > beginners. > This is the price of all innovation, but sometimes benefits are much > greater and the price is completely warranted. I do not feel this is the > case here. >
I just want to make sure you know that I 100% respect your feelings on this RFC. I can't comprehensively argue against them, so I won't try. I'll only say that I don't expect to see |> in rampant use in the next two years, maybe not in five. But that's okay, because that feature will (I hope) be there for private codebases soon, and public codebases later, and I believe it will make code more readable. -Sara

Larry Garfield

10 years ago
On 07/20/2016 07:42 PM, Sara Golemon wrote:
> With the branching of 7.1, and after some reflection on the previous > feedback, I'd like to reopen discussion of the Pipe Operator RFC > https://wiki.php.net/rfc/pipe-operator which I had previously put on > hold. I've changed much of the argument wording of the proposal, but > not the substantive feature set. If you still feel it's unworkable, > I'd like to encourage you to respond with what you think would make it > workable (if anything). Thanks. > > -Sara
I am still generally in favor of this proposal. Especially when dealing with nested array functions this operator would be a big boon to readability. However, the introduction discusses fluent chained methods of objects, and states " This RFC aims to improve code readability by bringing fluent expressions to functional and OOP libraries not originally designed for the task." The examples, however, all seem to be centered around procedural calls. (A static method call is the same thing as a procedural function call in this respect.) When dealing with methods on an object, it seems it wouldn't offer much. This other recent discussion/proposal for a "Cascade" operator seems like it would handle the OOP/method case much better: http://news.php.net/php.internals/94466 Note: I am not suggesting one is a substitute for the other; rather, that they are complementary by addressing different parts of the problem space, and the Pipe RFC should likely not emphasize OOP usage potential as I see not a great deal there. I am still in favor of it, but let's not over-state its use cases. PS: I am very disappointed that you chose to name the $$ token T_PIPE_VARIABLE and not T_BLINGBLING. --Larry Garfield

Sara Golemon

10 years ago
On Wed, Jul 20, 2016 at 8:50 PM, Larry Garfield <larry@garfieldtech.com> wrote:
> I am still generally in favor of this proposal. Especially when dealing > with nested array functions this operator would be a big boon to > readability. >
That's honestly my 90% use-case as well. array_merge and array_filter in particular.
> However, the introduction discusses fluent chained methods of objects, and > states " This RFC aims to improve code readability by bringing fluent > expressions to functional and OOP libraries not originally designed for the > task." The examples, however, all seem to be centered around procedural > calls. (A static method call is the same thing as a procedural function > call in this respect.) When dealing with methods on an object, it seems it > wouldn't offer much. >
In this context, I'd argue instance method calls aren't much different from static method calls either, but I wanted to avoid too many abstract/contrived examples. I suppose one might do something like: return $this->loadConfig() |> $arg->useConfig($$) |> $this->loadUser($$) |> array_merge($$, $this->userDefaults); But the PSR7 example is already contrived as it is.
> This other recent discussion/proposal for a "Cascade" operator seems like it > would handle the OOP/method case much better: > > http://news.php.net/php.internals/94466 > > Note: I am not suggesting one is a substitute for the other; rather, that > they are complementary by addressing different parts of the problem space, > and the Pipe RFC should likely not emphasize OOP usage potential as I see > not a great deal there. I am still in favor of it, but let's not over-state > its use cases. >
Fair enough. They certainly complement one another and I wouldn't argue either is a one-job-fits-all solution. I wasn't trying to emphasize OOP usage so much as include it as applicable. I think we might actually be agreeing in principle even if we're diverging in our word choices. :)
> PS: I am very disappointed that you chose to name the $$ token > T_PIPE_VARIABLE and not T_BLINGBLING. >
I leave the silly token names to Ze'ev/Andi (T_PAAMAYIM_NEKUDOTAYIM) and Davey (T_SPACESHIP). I am nothing if not entirely serious and professional. ;p -Sara P.S. - I'm totes going to make that a secondary voting choice now. Name the token, 50% majority wins.

Stefan Neufeind

10 years ago
On 21.07.2016 06:37, Sara Golemon wrote:
> On Wed, Jul 20, 2016 at 8:50 PM, Larry Garfield <larry@garfieldtech.com> wrote:
[...]
> return $this->loadConfig() > |> $arg->useConfig($$) > |> $this->loadUser($$) > |> array_merge($$, $this->userDefaults); > > But the PSR7 example is already contrived as it is. > >> This other recent discussion/proposal for a "Cascade" operator seems like it >> would handle the OOP/method case much better: >> >> http://news.php.net/php.internals/94466 >> >> Note: I am not suggesting one is a substitute for the other; rather, that >> they are complementary by addressing different parts of the problem space, >> and the Pipe RFC should likely not emphasize OOP usage potential as I see >> not a great deal there. I am still in favor of it, but let's not over-state >> its use cases. >> > Fair enough. They certainly complement one another and I wouldn't > argue either is a one-job-fits-all solution.
[...] Hi, Would joining the two be an option? If $$ is in the parameter-list, use that as the position for the parameter. If not, use the parameter as first argument? Kind regards, Stefan

Larry Garfield

10 years ago
On Wed, Jul 20, 2016, at 11:37 PM, Sara Golemon wrote:
> > However, the introduction discusses fluent chained methods of objects, and > > states " This RFC aims to improve code readability by bringing fluent > > expressions to functional and OOP libraries not originally designed for the > > task." The examples, however, all seem to be centered around procedural > > calls. (A static method call is the same thing as a procedural function > > call in this respect.) When dealing with methods on an object, it seems it > > wouldn't offer much. > > > In this context, I'd argue instance method calls aren't much different > from static method calls either, but I wanted to avoid too many > abstract/contrived examples. > > I suppose one might do something like: > > return $this->loadConfig() > |> $arg->useConfig($$) > |> $this->loadUser($$) > |> array_merge($$, $this->userDefaults); > > But the PSR7 example is already contrived as it is. > > > This other recent discussion/proposal for a "Cascade" operator seems like it > > would handle the OOP/method case much better: > > > > http://news.php.net/php.internals/94466 > > > > Note: I am not suggesting one is a substitute for the other; rather, that > > they are complementary by addressing different parts of the problem space, > > and the Pipe RFC should likely not emphasize OOP usage potential as I see > > not a great deal there. I am still in favor of it, but let's not over-state > > its use cases. > > > Fair enough. They certainly complement one another and I wouldn't > argue either is a one-job-fits-all solution. I wasn't trying to > emphasize OOP usage so much as include it as applicable. I think we > might actually be agreeing in principle even if we're diverging in our > word choices. :)
I agree. I'm entirely on board with the feature; more just critiquing the RFC intro text, which mentions OOP fluency as a use case, which I think is an over-reach. It's a useful enough feature even without talking about that, and it seems we agree that the syntax when used with methods is a bit awkward.
> P.S. - I'm totes going to make that a secondary voting choice now. > Name the token, 50% majority wins.
:-) --Larry Garfield

Rasmus Schultz

10 years ago
FWIW, I've read the manual page for the Hack page, and the RFC, a couple of times now, and I simply don't understand it. Are most PHP developers going to understand this feature, the meaning of $$, and when/how to use this? Are they going to be able to read code written in this way? To your knowledge, are there any other languages where this feature is found, or is it another one of those exotic features currently found in Hack and nowhere else? (I know a bunch of languages, and this feature doesn't ring any bells.) How does this feature compare with the cascade operator more commonly found in other languages? I mean, maybe it's just me, because I'm familiar with the cascade operator from other languages - but it seems simpler, more intuitive, easier to pick up, and appears to solve most of the same problems? If so, perhaps it would be right to consider the cascade operator as an alternative to this feature. I know that Hack may be closer in nature to PHP than some other languages, but if someone is familiar with both, likely they're not coming from Hack and moving to PHP, they're likely moving from PHP to Hack, so language similarity might not be the best argument for referencing Hack on this point, as opposed to referencing other languages... It seems to me, the main difference between the pipe operator and a cascade operator, is the anonymous context variable $$ created by the pipe operator - I think, partially, this is what makes those expression hard to read; the context changes (or does it?) along the way, but the (nameless) symbol used to reference those objects, in the same expression, are identical. Rather than writing extremely long expressions, as demonstrated in the RFC, I think, personally, if this feature were introduced, I'd lean more on intermediary variables, with names, that clarify the meaning - referencing a bunch of intermediaries with a nameless variable doesn't help readability at all, in my opinion. In contrast, I have no issue reading expressions with the cascade operator; again, maybe that's just because I'm familiar with that operator from other languages, but I don't think the nameless $$ variable helps readability or understanding. Just my two cents. On Fri, Jul 22, 2016 at 5:54 PM, Larry Garfield <larry@garfieldtech.com> wrote:

Rowan Collins

10 years ago
On 23/07/2016 12:15, Rasmus Schultz wrote:
> I mean, maybe it's just me, because I'm familiar with the cascade operator > from other languages - but it seems simpler, more intuitive, easier to pick > up, and appears to solve most of the same problems? If so, perhaps it would > be right to consider the cascade operator as an alternative to this feature.
They're not really the same thing at all; in some ways they're actually opposites. The cascade operator is a way of discarding the result of an object-oriented expression, and reusing the same context repeatedly. The pipe operator is a way of capturing the result of a procedural expression, and passing it forward to the next expression.
> It seems to me, the main difference between the pipe operator and a cascade > operator, is the anonymous context variable $$ created by the pipe operator > - I think, partially, this is what makes those expression hard to read; the > context changes (or does it?) along the way, but the (nameless) symbol used > to reference those objects, in the same expression, are identical.
Yes, the $$ means "result of last expression". In essence, it's a bit like Perl's $_ variable, except that it doesn't exist outside the pipe syntax. It has to exist to say where you're going to use that result in the next expression. In the cascade operator, you don't need a notation for it, because the context is always on the left of the operator: $foo ->>setBar(1) // context is $foo->... ->>setBar(2); // context is still $foo->... But again, this isn't the primary difference between the operators; the difference is that one is a way of discarding results, the other is a way of carrying results forward. Regards,
-- Rowan Collins [IMSoP]

Sara Golemon

10 years ago
On Sat, Jul 23, 2016 at 4:15 AM, Rasmus Schultz <rasmus@mindplay.dk> wrote:
> FWIW, I've read the manual page for the Hack page, and the RFC, a couple of > times now, and I simply don't understand it. >
Perhaps the documentation needs clarifying then.
> Are most PHP developers going to understand this feature, the meaning of > $$, and when/how to use this? >
Yes. PHP developers are excellent at Google and StackOverflow.
> Are they going to be able to read code written in this way? >
Yes.
> To your knowledge, are there any other languages where this feature is > found, or is it another one of those exotic features currently found in > Hack and nowhere else? (I know a bunch of languages, and this feature > doesn't ring any bells.) >
Elixir, F#, Swift (via library extension), ISTR a few others when I was researching a few months ago, but can't recall them offhand.
> How does this feature compare with the cascade operator more commonly found > in other languages? >
To turn your previous question around, what languages? I see them complementing one another, serving different goals and solving different problems. I suppose you could ask how this compares with short ternaries, coalesce, or bitwise xor, and the question will make as much sense.
> I mean, maybe it's just me, because I'm familiar with the cascade operator > from other languages - but it seems simpler, more intuitive, easier to pick > up, and appears to solve most of the same problems? If so, perhaps it would > be right to consider the cascade operator as an alternative to this feature. >
I would rather consider them both since they solve different problems in different ways.
> I know that Hack may be closer in nature to PHP than some other languages, > but if someone is familiar with both, likely they're not coming from Hack > and moving to PHP, they're likely moving from PHP to Hack, so language > similarity might not be the best argument for referencing Hack on this > point, as opposed to referencing other languages... >
Fair point, I'll add mentioned of the above languages to the RFC.
> It seems to me, the main difference between the pipe operator and a cascade > operator, is the anonymous context variable $$ created by the pipe operator > - I think, partially, this is what makes those expression hard to read; the > context changes (or does it?) along the way, but the (nameless) symbol used > to reference those objects, in the same expression, are identical. >
It's also what makes the cascade operator unable to solve all the problems which the pipe operator is capable of solving. Cascade applies to a very narrow band of instance method calls. Pipe applies best to static methods and procedural functions (which some applicability to methods). The flexibility of being able to place that lhs element in an arbitrary location is what makes it powerful.
> Rather than writing extremely long expressions, as demonstrated in the RFC, > I think, personally, if this feature were introduced, I'd lean more on > intermediary variables, with names, that clarify the meaning - referencing > a bunch of intermediaries with a nameless variable doesn't help readability > at all, in my opinion. >
The RFC states why this may not be a preferred course. How do we know, at a glance, that these well named intermediates are/aren't used later in the scope? What happens to destructor ordering when the variable lives till the end of the function? How does this impact optimization potential?
> In contrast, I have no issue reading expressions with the cascade operator; > again, maybe that's just because I'm familiar with that operator from other > languages, but I don't think the nameless $$ variable helps readability or > understanding. >
You keep acting as if pipe vs cascade is even a competition. It's not. They're different solutions to different problems which require different approaches. -Sara

David Rodrigues

10 years ago
This is a great idea in general, but I think that this kind of operator is not the ideal (expect for $$ that seems very good). Some possibilities to think about: |> (as suggested) seems strange and not very clear, mainly in linear calls --> can be too long, but can make more sense or continuing, but can confuse with simple -> $> seems like terminal, but can tell like "keep this root-variable and run it", bad for linear too <- is short, maybe can tells "call it and return to root-variable", in linear can be confused with "minus" minus operation ($x<-a()) => is short, but can be confused why array syntax, but good for linear .. (like Dart) is short, but can be confused why a (double?) concat, not seems PHP in general (but still a good option) Another option is make calls without define an operator, the problem is that can be not clear or then cause break changes (very bad for linear). Or defining a new keyword, but it can be exhaustive or reduce readability. Should be think about the linear readability too, for instance: $object->a()->b()->c() vs. $object|>a()|>b()|>c(). Examples: http://pastebin.com/rguUSxDr It can works to avoid matroska (as initial suggestion) but for objects too. PHP should identify if this operator is used over object or other type (that allows the use of $$). The problem is it can be confused: are you executing an object method or another function with the object? Like in: $clockObject |> setHour(12) |> is_string($$). 'is_string' is from Clock or PHP native function? Example: http://pastebin.com/t79kjaHQ

Rowan Collins

10 years ago
On 21/07/2016 13:39, David Rodrigues wrote:
> This is a great idea in general, but I think that this kind of > operator is not the ideal (expect for $$ that seems very good). > > Some possibilities to think about: > > |> (as suggested) seems strange and not very clear, mainly in linear calls
[...]
> Should be think about the linear readability too, for instance: > $object->a()->b()->c() vs. $object|>a()|>b()|>c().
I think it's quite clear, personally, particularly if you just add a bit of whitespace: $thing |> a($$) |> b($$) |> c($$) The |> looks kind of like a triangle pointing to the next pipe.
> It can works to avoid matroska (as initial suggestion) but for objects too. > PHP should identify if this operator is used over object or other type > (that allows the use of $$). > The problem is it can be confused: are you executing an object method > or another function with the object? > Like in: $clockObject |> setHour(12) |> is_string($$). 'is_string' is > from Clock or PHP native function?
I think you may be confusing this with the other, somewhat complementary, proposal of a "method cascade" operator. Since this operator always takes the result of one expression as the input to the next, the equivalent for object methods already exists: -> Your example wouldn't do anything much, because there's no $$ in setHour(12), but: $clockObject -> setHour(12) |> is_string($$) would be equivalent to: is_string( $clockObject -> setHour(12) ) That said, if there's a possibility we'll have both features, we need to think about how the operators will look next to each other, and how easy it will be to pick the right one. Regards,
-- Rowan Collins [IMSoP]

Rowan Collins

10 years ago
On 21/07/2016 00:42, Sara Golemon wrote:
> With the branching of 7.1, and after some reflection on the previous > feedback, I'd like to reopen discussion of the Pipe Operator RFC > https://wiki.php.net/rfc/pipe-operator which I had previously put on > hold. I've changed much of the argument wording of the proposal, but > not the substantive feature set. If you still feel it's unworkable, > I'd like to encourage you to respond with what you think would make it > workable (if anything). Thanks.
It looks like the examples are all still function calls. Could you clarify what expressions would be acceptable on the right-hand side? In particular, can I assign to a variable at the end of the pipe? foo() |> bar($$) |> $result = $$; As discussed before, I think pipes would be most useful if values could "exit on the right". For which I would also like to be able to do this: foo() |> bar($$) |> return $$; (Or, as discussed, special syntax for one or both of these.) Regards,
-- Rowan Collins [IMSoP]

Sara Golemon

10 years ago
On Thu, Jul 21, 2016 at 6:59 AM, Rowan Collins <rowan.collins@gmail.com> wrote:
> On 21/07/2016 00:42, Sara Golemon wrote: >> >> With the branching of 7.1, and after some reflection on the previous >> feedback, I'd like to reopen discussion of the Pipe Operator RFC >> https://wiki.php.net/rfc/pipe-operator which I had previously put on >> hold. I've changed much of the argument wording of the proposal, but >> not the substantive feature set. If you still feel it's unworkable, >> I'd like to encourage you to respond with what you think would make it >> workable (if anything). Thanks. > > It looks like the examples are all still function calls. Could you clarify > what expressions would be acceptable on the right-hand side? >
Any non-terminal expression.
> In particular, can I assign to a variable at the end of the pipe? > > foo() |> bar($$) |> $result = $$; >
Sure. ($result = $$) is an expression which returns the assigned value, so it's a valid non-terminal. $alsoResult = foo() |> bar($$) |> $result = $$; var_dump($alsoResult === $result); // bool(true)
> As discussed before, I think pipes would be most useful if values could > "exit on the right". For which I would also like to be able to do this: > > foo() |> bar($$) |> return $$; >
Are you picturing the return statement returning from the current function? Or "returning" from the current pipe chain? I think you mean the former, in which case I'd ask how that'd better/worse than: return foo() |> bar($$);
> (Or, as discussed, special syntax for one or both of these.) >
As above, I don't think special syntax adds anything for either of these cases. -Sara

Rowan Collins

10 years ago
On 21/07/2016 22:28, Sara Golemon wrote:
> Are you picturing the return statement returning from the current > function? Or "returning" from the current pipe chain? > > I think you mean the former, in which case I'd ask how that'd better/worse than: > > return foo() |> bar($$);
I do indeed mean returning from the current function. I went into more detail (perhaps too much!) on the previous thread, but the basic premise is the pipe operator gives you code that reads left to right. Adding an element where you have to jump back to the beginning of the expression feels like it defeats that. You picked an example with a very short pipeline, and the "return" is fairly obvious; but then "return bar(foo());" is not a great candidate for using the operator in the first place. Take a longer example: return loadConfig() |> buildDic($$) |> getApp($$) |> getRouter($$) |> getDispatcher($$, $request) |> dispatchBusinessLogic($$, $request, new Response()) |> renderResponse($$) |> buildPsr7Response($$) |> emit($$); If you read through that pipeline, you get down to emit($$), and then have to scan back up to figure out where result of that is going to end up. Compare: loadConfig() |> buildDic($$) |> getApp($$) |> getRouter($$) |> getDispatcher($$, $request) |> dispatchBusinessLogic($$, $request, new Response()) |> renderResponse($$) |> buildPsr7Response($$) |> emit($$) |> return $$; Here you can read through all the steps in order, right up to the last action, which is returning the resulting value. Even the name "pipe" is suggesting that something goes in one end, and comes out the other, so having the output pop out next to the input just feels weird. Regards,
-- Rowan Collins [IMSoP]

Sara Golemon

10 years ago
On Thu, Jul 21, 2016 at 2:56 PM, Rowan Collins <rowan.collins@gmail.com> wrote:
> On 21/07/2016 22:28, Sara Golemon wrote: >> >> Are you picturing the return statement returning from the current >> function? Or "returning" from the current pipe chain? >> >> I think you mean the former, in which case I'd ask how that'd better/worse >> than: >> >> return foo() |> bar($$); > > I do indeed mean returning from the current function. I went into more > detail (perhaps too much!) on the previous thread, but the basic premise is > the pipe operator gives you code that reads left to right. Adding an element > where you have to jump back to the beginning of the expression feels like it > defeats that. >
Ah! I understand your point now. Indeed, in terms of code-scan, there's something of a whiplash effect going on. Now I understand the motivation behind $> assignment and/or using a terminal like `return $$` at the end. Adding in support for some terminals (like return) could make sense, it's an exception to a rule, but it's a reasonable looking one (at first glance, anyway). The assign to var at the end however, is something I'd rather handle with the following: foo() |> bar($$) |> $baz = qux($$); Which is both legal with the syntax as-is, and entirely readable without adding an extra operator. -Sara

David Rodrigues

10 years ago
It's possible to use the tilde ~ easyly on keyboards? For on BR/ABNT2 is easy. So maybe use ~> as operator could be fine, instead of the triangle |>, and linear sounds good too, like: $string~>escape($$)~>dump($$); It's used currently on PHP for a bitwise operation (not), so I think that the usage are not a problem in general. Too will not have a conflict, because ~> no make any sense to PHP today. 2016-07-22 2:52 GMT-03:00 Sara Golemon <pollita@php.net>:
> On Thu, Jul 21, 2016 at 2:56 PM, Rowan Collins <rowan.collins@gmail.com> wrote: >> On 21/07/2016 22:28, Sara Golemon wrote: >>> >>> Are you picturing the return statement returning from the current >>> function? Or "returning" from the current pipe chain? >>> >>> I think you mean the former, in which case I'd ask how that'd better/worse >>> than: >>> >>> return foo() |> bar($$); >> >> I do indeed mean returning from the current function. I went into more >> detail (perhaps too much!) on the previous thread, but the basic premise is >> the pipe operator gives you code that reads left to right. Adding an element >> where you have to jump back to the beginning of the expression feels like it >> defeats that. >> > Ah! I understand your point now. Indeed, in terms of code-scan, > there's something of a whiplash effect going on. Now I understand the > motivation behind $> assignment and/or using a terminal like `return > $$` at the end. > > Adding in support for some terminals (like return) could make sense, > it's an exception to a rule, but it's a reasonable looking one (at > first glance, anyway). > > The assign to var at the end however, is something I'd rather handle > with the following: > > foo() |> bar($$) |> $baz = qux($$); > > Which is both legal with the syntax as-is, and entirely readable > without adding an extra operator. > > -Sara > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php >
-- David Rodrigues

Björn Larsson

10 years ago
Den 2016-07-22 kl. 17:05, skrev David Rodrigues:
> It's possible to use the tilde ~ easyly on keyboards? > For on BR/ABNT2 is easy. So maybe use ~> as operator could be fine, > instead of the triangle |>, and linear sounds good too, like: > $string~>escape($$)~>dump($$); > > It's used currently on PHP for a bitwise operation (not), so I think > that the usage are not a problem in general. > Too will not have a conflict, because ~> no make any sense to PHP today.
There was an RFC proposing that operator for short closures, see: - https://wiki.php.net/rfc/short_closures Recall that the operator was a bit controversial due to e.g. japanese keyboard. Personally I liked the proposal and I think the "pipe" sign fit well into an pipe operator:) Regards //Björn Larsson

Joe Watkins

9 years ago
Morning Sara, This has generated some very decent discussion. It seems like time to put this to a vote, could you maybe find some time to do that please ? Alternatively, if there are outstanding issues that are stopping this going to a vote, could we know what they are, and maybe your plan to resolve them ? Cheers Joe On Mon, Jul 25, 2016 at 3:52 PM, Björn Larsson <bjorn.x.larsson@telia.com> wrote:

Yasuo Ohgaki

9 years ago
On Mon, Jul 25, 2016 at 11:52 PM, Björn Larsson <bjorn.x.larsson@telia.com> wrote:
> Den 2016-07-22 kl. 17:05, skrev David Rodrigues: > > It's possible to use the tilde ~ easyly on keyboards? >> For on BR/ABNT2 is easy. So maybe use ~> as operator could be fine, >> instead of the triangle |>, and linear sounds good too, like: >> $string~>escape($$)~>dump($$); >> >> It's used currently on PHP for a bitwise operation (not), so I think >> that the usage are not a problem in general. >> Too will not have a conflict, because ~> no make any sense to PHP today. >> > There was an RFC proposing that operator for short closures, see: > - https://wiki.php.net/rfc/short_closures > > Recall that the operator was a bit controversial due to > e.g. japanese keyboard. Personally I liked the proposal > and I think the "pipe" sign fit well into an pipe operator:)
I'm surprised someone noticed Japanese "~" char issue. We have "~" char issue, but it would not be problem for programmers. I guess you mentioned this issue. https://ja.wikipedia.org/wiki/%E6%B3%A2%E3%83%80%E3%83%83%E3%82%B7%E3%83%A5 http://qiita.com/kasei-san/items/3ce2249f0a1c1af1cbd2 They are written in Japanese. Please use google translate or similar. Wrongly configured keyboard could be another problem. We may ignore such environment. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Rowan Collins

10 years ago
On 22/07/2016 06:52, Sara Golemon wrote:
> Ah! I understand your point now. Indeed, in terms of code-scan, > there's something of a whiplash effect going on. Now I understand the > motivation behind $> assignment and/or using a terminal like `return > $$` at the end. > > Adding in support for some terminals (like return) could make sense, > it's an exception to a rule, but it's a reasonable looking one (at > first glance, anyway).
Glad it makes sense. :) I realise "return $$" would have to have some special handling, but it would feel more natural to me. I guess the only concern is what happens when a pipeline has a return terminal and is used in expression context: $foo = bar() |> baz($$) |> return $$; // theoretically translates to this invalid PHP: $foo = return baz(bar()); I'm not sure how easily the compiler would be able to pick up that that's an illegal construction. I was going to say that "yield" would be worth considering at the same time, but presumably that's already legal, because yield can appear as an expression (to receive variables sent into a co-routine). It's a shame neither "echo" nor "print" is useful for getting $$ out to screen and leaving it unchanged (echo doesn't work in expression context at all; print doesn't have a useful return value).
> The assign to var at the end however, is something I'd rather handle > with the following: > > foo() |> bar($$) |> $baz = qux($$); > > Which is both legal with the syntax as-is, and entirely readable > without adding an extra operator.
Yes, on reflection I think "|> $foo = $$" is probably easier to follow than extra syntax. I quite like the idea of a whole language where data always flows left-to-right, but we're used to that being what assignment looks like. It might be worth coming up with some examples to add to the RFC where $$ is used in an expression other than a function call, because I wasn't entirely sure when I read it if that was even allowed. It might also clear up some of the confusion around this being anything to do with OO. Off the top of my head, how about some maths: $foo * $bar |> 2 ** $$ |> sin($$ + 1) |> $$ / 20 |> $result = $$; Compiles to: $result = sin((2 ** ($foo * $bar)) + 1) / 20; Or: $temp = $foo * $bar; $temp = 2 ** $temp; $temp = sin($temp + 1); $result = $temp / 20; Regards,
-- Rowan Collins [IMSoP]

Sara Golemon

10 years ago
On Sat, Jul 23, 2016 at 8:15 AM, Rowan Collins <rowan.collins@gmail.com> wrote:
> Glad it makes sense. :) I realise "return $$" would have to have some > special handling, but it would feel more natural to me. I guess the only > concern is what happens when a pipeline has a return terminal and is used in > expression context: > > $foo = bar() |> baz($$) |> return $$; > // theoretically translates to this invalid PHP: > $foo = return baz(bar()); > > I'm not sure how easily the compiler would be able to pick up that that's an > illegal construction. >
Right, which is where I'm hesitant to go down that road.
> I was going to say that "yield" would be worth considering at the same time, > but presumably that's already legal, because yield can appear as an > expression (to receive variables sent into a co-routine). >
Yep. Perfectly valid as-is, so a non-issue.
> It's a shame neither "echo" nor "print" is useful for getting $$ out to > screen and leaving it unchanged (echo doesn't work in expression context at > all; print doesn't have a useful return value). >
Yeah, those pegs really don't fit into this hole...
> It might be worth coming up with some examples to add to the RFC where $$ is > used in an expression other than a function call, because I wasn't entirely > sure when I read it if that was even allowed. It might also clear up some of > the confusion around this being anything to do with OO. > > Off the top of my head, how about some maths: > > $foo * $bar > |> 2 ** $$ > |> sin($$ + 1) > |> $$ / 20 > |> $result = $$; > > Compiles to: > > $result = sin((2 ** ($foo * $bar)) + 1) / 20; > > Or: > > $temp = $foo * $bar; > $temp = 2 ** $temp; > $temp = sin($temp + 1); > $result = $temp / 20; >
Fair point, I took those as a given, but they should be added. (And yes, they're valid). -Sara

Levi Morrison

9 years ago
On Wed, Jul 20, 2016 at 5:42 PM, Sara Golemon <pollita@php.net> wrote:
> With the branching of 7.1, and after some reflection on the previous > feedback, I'd like to reopen discussion of the Pipe Operator RFC > https://wiki.php.net/rfc/pipe-operator which I had previously put on > hold. I've changed much of the argument wording of the proposal, but > not the substantive feature set. If you still feel it's unworkable, > I'd like to encourage you to respond with what you think would make it > workable (if anything). Thanks. > > -Sara > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php
I've talked to you about this RFC off-list, but I figured I should mention it on-list as well. I think we should make `|>` and `$$` two independent operators that work well together (rather than only together). The `|>` symbol would be the piping operator with these semantics: 1. Evaluate the left-hand side. 2. Evaluate the right-hand side. Assert that the result is callable. 3. Pass the result from 1. as the single argument to 2. The `$$` symbol would be the partial function application operator with these semantics: 1. When function application has `$$` as a parameter it becomes a partial application instead. This result of a partial application is a closure. 2. Each non-`$$` parameter is evaluated and then bound at that position. 3. Each `$$` will become a parameter to the closure which will be passed to the inner function call at its original position. 4. Each parameter and closed variable will be done by reference or by value depending on the function being called. The type will also be inherited. 5. The return type of the closure will be inherited from the function it is calling. As an optimization when `|>` and `$$` are used in conjunction there is no need to create closures. This would make the outlined semantics be equivalent to the currently proposed RFC when used together. What do the rest of you think about this instead?

Unnamed Person

9 years ago
Le 19/01/2017 à 13:54, Levi Morrison a écrit :
> The `|>` symbol would be the piping operator with these semantics: > 1. Evaluate the left-hand side. > 2. Evaluate the right-hand side. Assert that the result is callable. > 3. Pass the result from 1. as the single argument to 2.
May I suggest extending your 3rd rule to : when the right hand side has the form of a function call, insert the result from 1. as first argument of 2. This way, right hand side may specify additional arguments. Based on the fact that, in 99% of PHP builtin functions where the concept applies, the 'input' argument is the first one. Example : $string |> trim('.,;:') $string |> trim() IMO, not acceptable : $string |> trim Regards François

Levi Morrison

9 years ago
On Thu, Jan 19, 2017 at 11:12 AM, François Laupretre <flaupretre@free.fr> wrote:
> Le 19/01/2017 à 13:54, Levi Morrison a écrit : >> >> The `|>` symbol would be the piping operator with these semantics: >> 1. Evaluate the left-hand side. >> 2. Evaluate the right-hand side. Assert that the result is callable. >> 3. Pass the result from 1. as the single argument to 2. > > > May I suggest extending your 3rd rule to : when the right hand side has the > form of a function call, insert the result from 1. as first argument of 2. > This way, right hand side may specify additional arguments
If we only had `|>` this may be good but since we are also proposing `$$` then this renders your suggestion unnecessary: $string |> trim($$) Would work just fine with no performance overhead. Additionally, you could write: $input |> array_map($fn, $$) Or: $input |> array_filter($$, $fn) Basically, `$$` gives the flexibility of passing additional arguments and keeps `|>` simple. No need for additional rules for `|>`.

Unnamed Person

9 years ago
Le 19/01/2017 à 22:53, Levi Morrison a écrit :
> On Thu, Jan 19, 2017 at 11:12 AM, François Laupretre <flaupretre@free.fr> wrote: >> Le 19/01/2017 à 13:54, Levi Morrison a écrit : >>> The `|>` symbol would be the piping operator with these semantics: >>> 1. Evaluate the left-hand side. >>> 2. Evaluate the right-hand side. Assert that the result is callable. >>> 3. Pass the result from 1. as the single argument to 2. >> >> May I suggest extending your 3rd rule to : when the right hand side has the >> form of a function call, insert the result from 1. as first argument of 2. >> This way, right hand side may specify additional arguments > If we only had `|>` this may be good but since we are also proposing > `$$` then this renders your suggestion unnecessary: > > $string |> trim($$) > > Would work just fine with no performance overhead. > > Additionally, you could write: > > $input |> array_map($fn, $$) > > Or: > > $input |> array_filter($$, $fn) > > Basically, `$$` gives the flexibility of passing additional arguments > and keeps `|>` simple. No need for additional rules for `|>`.
Right, I just suggest to make the '$$' optional when used as first arg of a rhs call. Except complex cases like array_xx() functions which will generally require an explicit '$$', most cases will feature a '$$' as first arg of a function call. This may be considered as better because more explicit, but I think the case is prominent enough to justify this 'shortcut'. Another question: Will you accept several occurences of '$$' in a RHS ? Last, a cosmetic suggestion : replace '$$' with '$<' (more explicit as 'input data', imo). Regards François

Levi Morrison

9 years ago
On mobile, sorry for top posting. Multiple $$ means the resulting closure will accept multple arguments. I'm definitely against dropping the ($$) on the right hand side because it would use non standard symbol lookup rules. $x = trim; This normally will look up a constant, and then apply barewords if it doesn't exist. Let's not go down the road of special casing things. On Jan 20, 2017 3:53 AM, "François Laupretre" <flaupretre@free.fr> wrote:

Levi Morrison

9 years ago
On Fri, Jan 20, 2017 at 3:53 AM, François Laupretre <flaupretre@free.fr> wrote:

Levi Morrison

9 years ago
Oops, sorry for an email that just quotes others; mis-clicked send.
> Last, a cosmetic suggestion : replace '$$' with '$<' (more explicit as > 'input data', imo).
If we aren't going to use `$$` I'd like to use `_` or `__` which read similar to "fill in the blank" and has precedence in other languages. But at this stage I'd much rather focus on changing the general model to what I've proposed instead of what is outlined in the RFC. I care much more about the feature than the exact syntax for it.

Rasmus Schultz

9 years ago
Isn't `_` more generally used as a "discard" placeholder in most languages? At least in Swift, Go, Scala, Dart and C# (starting with v7) I think? I don't recall having seen it mean "fill in the blank". In what languages? On Fri, Jan 20, 2017 at 4:26 PM, Levi Morrison <levim@php.net> wrote:

Levi Morrison

9 years ago
On Tue, Jan 24, 2017 at 12:25 PM, Rasmus Schultz <rasmus@mindplay.dk> wrote:
> Isn't `_` more generally used as a "discard" placeholder in most languages? > > At least in Swift, Go, Scala, Dart and C# (starting with v7) I think? > > I don't recall having seen it mean "fill in the blank". In what languages? > > > On Fri, Jan 20, 2017 at 4:26 PM, Levi Morrison <levim@php.net> wrote: >> >> Oops, sorry for an email that just quotes others; mis-clicked send. >> >> > Last, a cosmetic suggestion : replace '$$' with '$<' (more explicit as >> > 'input data', imo). >> >> If we aren't going to use `$$` I'd like to use `_` or `__` which read >> similar to "fill in the blank" and has precedence in other languages. >> >> But at this stage I'd much rather focus on changing the general model >> to what I've proposed instead of what is outlined in the RFC. I care >> much more about the feature than the exact syntax for it. >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: http://www.php.net/unsub.php >> >
Scala does use it this way. It also uses it in pattern matching to mean "match anything else" or "I don't care about this one".

Stephen Reay

9 years ago
As a userland developer I feel $$ (or some variation starting with $) is reasonably natural - it's a variation on a regular variable. Sent from my iPhone

Ryan Pallas

9 years ago
On Thu, Jan 19, 2017 at 5:54 AM, Levi Morrison <levim@php.net> wrote:
> On Wed, Jul 20, 2016 at 5:42 PM, Sara Golemon <pollita@php.net> wrote: > > With the branching of 7.1, and after some reflection on the previous > > feedback, I'd like to reopen discussion of the Pipe Operator RFC > > https://wiki.php.net/rfc/pipe-operator which I had previously put on > > hold. I've changed much of the argument wording of the proposal, but > > not the substantive feature set. If you still feel it's unworkable, > > I'd like to encourage you to respond with what you think would make it > > workable (if anything). Thanks. > > > > -Sara > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: http://www.php.net/unsub.php > > I've talked to you about this RFC off-list, but I figured I should > mention it on-list as well. I think we should make `|>` and `$$` two > independent operators that work well together (rather than only > together). > > The `|>` symbol would be the piping operator with these semantics: > > 1. Evaluate the left-hand side. > 2. Evaluate the right-hand side. Assert that the result is callable. > 3. Pass the result from 1. as the single argument to 2. > > When you say assert the right hand side is callable, does that mean to
call an object method, you would do [$obj, 'method']? What about functions, is it just the name like $str |> trim, or is it $str |> trim()? Neither makes sense to me in the context of PHP since methods/functions are named objects, which is why when you pass a callback you have to give the string name of the function instead of just the name of the function, IE array_filter($arr, 'trim') vs array_filter($arr, trim).

Rowan Collins

9 years ago
On Thu, Jan 19, 2017 at 5:54 AM, Levi Morrison <levim@php.net> wrote:
> I've talked to you about this RFC off-list, but I figured I should > mention it on-list as well. I think we should make `|>` and `$$` two > independent operators that work well together (rather than only > together).
Firstly, Levi, can I say I really like this line of thinking at first sight. As long as we can avoid it becoming too cryptically Perlish... On 19/01/2017 22:17, Ryan Pallas wrote:
> > When you say assert the right hand side is callable, does that mean to > call an object method, you would do [$obj, 'method']? What about functions, > is it just the name like $str |> trim, or is it $str |> trim()?
This is a good point. The difference between the pipe operator as proposed by Sara and the combination of two separate operators is that in Sara's proposal you'd always write this: $str |> trim($$) But in Levi's proposal as I understand it, the right-hand side is not syntax, it's just constrained to be callable, so the simpler (but rather ugly) form would be: $str |> 'trim' On its own, trim($$) rather pointlessly wraps a function with one argument into another function, still with one argument, effectively short-hand for Closure::fromCallable('trim') [incidentally, fromCallable isn't actually listed in the documentation yet]. Since ($$) would leave a closure effectively unchanged, you could actually write: $str |> trim($$)($$)($$)($$) And interestingly, the $$ magic couldn't be used to turn a function with one argument into one with zero, because trim($$)($foo) actually executes the function. This all feels fiddly for the same reason I dislike generators being introduced with "function" rather than their own keyword: it's one syntax hiding behind another. Which is a shame, because as I say, I liked the general idea. Regards,
-- Rowan Collins [IMSoP]

Ryan Pallas

9 years ago
On Thu, Jan 19, 2017 at 4:08 PM, Rowan Collins <rowan.collins@gmail.com> wrote:
> > > On 19/01/2017 22:17, Ryan Pallas wrote: > >> >> When you say assert the right hand side is callable, does that mean to >> call an object method, you would do [$obj, 'method']? What about >> functions, >> is it just the name like $str |> trim, or is it $str |> trim()? >> > > This is a good point. The difference between the pipe operator as proposed > by Sara and the combination of two separate operators is that in Sara's > proposal you'd always write this: > > $str |> trim($$) > > But in Levi's proposal as I understand it, the right-hand side is not > syntax, it's just constrained to be callable, so the simpler (but rather > ugly) form would be: > > $str |> 'trim' >
See I don't like that at all, I hate having to put functions/methods in strings, as find usages and refactor tools generally don't find the strings. But sometimes I have to yield my preference to those who outrank me (aka those with voting power)

Levi Morrison

9 years ago
On Thu, Jan 19, 2017 at 4:55 PM, Ryan Pallas <derokorian@gmail.com> wrote:
> On Thu, Jan 19, 2017 at 4:08 PM, Rowan Collins <rowan.collins@gmail.com> > wrote: >> >> >> On 19/01/2017 22:17, Ryan Pallas wrote: >> >>> >>> When you say assert the right hand side is callable, does that mean to >>> call an object method, you would do [$obj, 'method']? What about >>> functions, >>> is it just the name like $str |> trim, or is it $str |> trim()? >>> >> >> This is a good point. The difference between the pipe operator as proposed >> by Sara and the combination of two separate operators is that in Sara's >> proposal you'd always write this: >> >> $str |> trim($$) >> >> But in Levi's proposal as I understand it, the right-hand side is not >> syntax, it's just constrained to be callable, so the simpler (but rather >> ugly) form would be: >> >> $str |> 'trim' >> > > See I don't like that at all, I hate having to put functions/methods in > strings, as find usages and refactor tools generally don't find the > strings. But sometimes I have to yield my preference to those who outrank > me (aka those with voting power)
While this would be permitted: $str |> 'trim' So would: $str |> trim($$) I empathize that you don't like string-name callables (I really don't like them either) but this RFC helps avoid the string if you want to. Consider // without my proposal: array_map('trim', $input) // with it: array_map(trim($$), $input) Which makes a bigger difference for namespaced functions: // without my proposal: array_map('namespaced\func\map', $input) // with it (assuming you are in the correct namespace or // did `use function namespaced\func\map`: array_map(map($$), $input) So to summarize, the right-hand-side of `|>` being callable doesn't mean you "have to" put it in a string; you can pair it with `$$` to avoid that.

Rowan Collins

9 years ago
On 20 January 2017 00:59:59 GMT+00:00, Levi Morrison <levim@php.net> wrote:
> >I empathize that you don't like string-name callables (I really don't >like them either) but this RFC helps avoid the string if you want to. >Consider > > // without my proposal: > array_map('trim', $input) > > // with it: > array_map(trim($$), $input)
Sure, like I said in my previous message, ($$) acts as a shorthand for Closure::fromCallable on any callable that takes one argument. But syntax for getting a reference to a function has been discussed before, and it would be a shame to be able to do it for this special case but not others. Straw manning, if name::fn got a reference to a function from its name, you could do: $foo |> trim::fn Which makes more sense than using a partial application operator without applying anything. Regards,
-- Rowan Collins [IMSoP]