Re: Cascade Operator (was Re: Proposal for php7 class method return)

php.internals

Michael Morris

10 years ago
On Mon, Jul 11, 2016 at 1:55 PM, Michał Brzuchalski < michal.brzuchalski@gmail.com> wrote:
> 11 lip 2016 18:31 "Rasmus Schultz" <rasmus@mindplay.dk> napisał(a): > > > > > what's the actual added value of this sort of operator? > > > > The only direct value to the language is brevity - mere convenience. > > > > But I think the biggest indirectly added value, is that this will > > discourage people from the chainable methods anti-pattern - so this > > has value to the community; those who write chainable methods can > > stop, and those who want chainable methods can get a wider choice of > > libraries that were previously too verbose in use for their taste. > > > > > For this sort of chaining I'd propose, in addition to the cascade > operator, > > > the chain operator. This would work like the cascade operator except > that > > > the return of the function is implicitly the first parameter of the > next > > > argument in the chain > > > > I don't like this idea, at all - I think we should aim for something > > consistent with other languages. Per the Dart spec: > > > > > A cascaded method invocation expression of the form e..suffix is > equivalent to the expression (t){t.suffix; return t;}(e). > > > > In other words, the expression always evaluates as the object, which > > is fine for most cases, e.g. for everything you're doing with > > chainable methods today - which can't actually return any values, > > since they return $this. Note that something like PSR-7's HTTP > > immutable models are actually factory methods, e.g. use-cases not > > applicable to the cascade operator. > > > > The other marginal use case perhaps is cases where a builder of some > > sort ends with a call to a factory method - this can be done without > > adding a second operator, by using parens in a similar fashion to Dart > > and others, e.g.: > > > > $object = ($builder > > ->>setFoo(1) > > ->>setBar(2) > > ->>setBaz(3) > > )->build(); > > > > Or obviously: > > > > $builder > > ->>setFoo(1) > > ->>setBar(2) > > ->>setBaz(3); > > > > $object = $builder->build(); > > > > Regarding syntax - I feel the natural choice, e.g. similar to "." vs > > "..", would be a longer arrow --> but that's ambiguous. (decrement > > operator, greater than operator) > > > > The proposed |> operator looks horrible and is very awkward to type, > > at least on both American and Danish keyboard - I use both. (it reads > > like "or greater than" in my mind, so much so that glancing over > > Sara's proposal earlier, I didn't even understand what it was.) > > > > Would something like ->> be ambiguous as well? That's fairly close too > > - a double-headed arrow, not unlike the double dots of other > > languages... > > > > IMHO double-headed arrow looks pretty nice and whole idea is great. Very > big +1 for this feature > > >
Agreed, but what about static methods? Triple colon perhaps? A::setFoo(1) :::setBar(2) :::setBaz(3); And I do agree that the double period is cleaner, but the bus left the station a very long time ago (PHP 3 at least) by making . the connotation operator. Or at least I think so. If the parser could deal with it double period would be best because it could apply to both contexts. $object->setFoo(1) ..setBar(2) ..setBaz(3); A_Class::setFoo(1) ..setBar(2) ..setBaz(3); But again, I don't know how feasible the above is since I know next to nothing about internals.

Rasmus Schultz

10 years ago
IMO, static methods have very little need for this feature - you rarely need to make repeated series of static calls and static property assignments. Let's not complicate this. On Tue, Jul 12, 2016 at 3:54 PM, Michael Morris <tendoaki@gmail.com> wrote:

Rowan Collins

10 years ago
On 12/07/2016 14:54, Michael Morris wrote:
> Agreed, but what about static methods? Triple colon perhaps? > > A::setFoo(1) > :::setBar(2) > :::setBaz(3);
This is a rather different feature, because you can't really express that as an expression returning something. What is $result set to if I run "$result = A:::setFoo(1)"? Or, equivalently, what is the value of the chain you've written? (Presumably, the "::" on the first line should be a ":::", otherwise I'm even less sure how to read it...) I think saying "if you want the cascade operator, you have to use an instance, not static methods" is reasonable enough. Especially with the perennial discussion about namespaced functions being better than classes with lots of static methods (if only we had function autoloading, etc, etc). Somebody quoted a concise explanation of the cascade operator earlier, which bears repeating, in PHP context: // Proposed $result = $foo->>bar(); // Valid in PHP 7 $result = ( function($subject){ $subject->bar(); return $subject; } )( $foo ); // Long-hand $foo->bar(); // discard return result $result = $foo; There's no magic needed to create longer chains, or combine this with other operators; it's not a transform done to the source code, just a normal expression. Regards,
-- Rowan Collins [IMSoP]