Methods which auto-return the class instance

php.internals

joke2k

3 years ago
Hi folks, What do you think about having a method which returns the class instance `$this` by default only IF its return type is set as `self`? It is very common for fluent class methods to have a verbose `return $this;` ending in their body. But If you have declared `self` as return type into a non-static class method you have only two options to return: - the $this object - another instance of the same class or subclass ... in order to avoid a return type error. My proposal is to set the instruction `return $this;` as optional for non-static class methods with `self` declared as return type. Example: ``` class Counter { public function __construct(private int $counter = 0) {} public function hit(): self { $this->counter++; } public function print(): self { echo $this->counter; } public function split(): self { return new self($this->counter); } } $main = (new Counter)->hit()->hit()->hit()->print() // 3 $sub = $main->split()->hit()->print() // 4 ``` Thank you for reading my proposal, please let me know if you like it or if there are any issues with this. Regards, Daniele

Claude Pache

3 years ago
> Le 23 déc. 2022 à 01:08, joke2k <joke2k@gmail.com> a écrit : > > Hi folks, > > What do you think about having a method which returns the class instance > `$this` by default only IF its return type is set as `self`? > > It is very common for fluent class methods to have a verbose `return > $this;` ending in their body. > But If you have declared `self` as return type into a non-static class > method you have only two options to return: > > - the $this object > - another instance of the same class or subclass > > ... in order to avoid a return type error.
It is still two options, and it is not clear in general which one to pick. You could also say that, if you have `object` as return type, there are two options to avoid a return type error: either return the `$this` object, or return another object.
> > My proposal is to set the instruction `return $this;` as optional for > non-static class methods with `self` declared as return type.
I’d rather have a syntax saying explicitly that you want to return $this, rather than letting the interpreter guess what you meant. The obvious one is: ```php public function hit(): $this { $this->counter++; } ``` Here, there is only one possible return value, and therefore the `return` instruction might be reasonably omitted. The real question is: Is it worth to add special cases for some specific return values? —Claude

Lynn

3 years ago
On Fri, Dec 23, 2022 at 10:33 AM Claude Pache <claude.pache@gmail.com> wrote:
> > ```php > public function hit(): $this { $this->counter++; } > ``` > > Here, there is only one possible return value, and therefore the `return` > instruction might be reasonably omitted. > > The real question is: Is it worth to add special cases for some specific > return values? >
We do have true, false, and null as return types ( https://www.php.net/releases/8.2/en.php#null_false_true_types). I'm personally not opposed to having `$this` as return type, but it also starts getting close to short function notations.

Michał Brzuchalski

3 years ago
Hi Daniele and Claude, pt., 23 gru 2022 o 10:33 Claude Pache <claude.pache@gmail.com> napisał(a):
> > > Le 23 déc. 2022 à 01:08, joke2k <joke2k@gmail.com> a écrit : > > > > Hi folks, > > > > What do you think about having a method which returns the class instance > > `$this` by default only IF its return type is set as `self`? > > > > It is very common for fluent class methods to have a verbose `return > > $this;` ending in their body. > > But If you have declared `self` as return type into a non-static class > > method you have only two options to return: > > > > - the $this object > > - another instance of the same class or subclass > > > > ... in order to avoid a return type error. > > It is still two options, and it is not clear in general which one to pick. > You could also say that, if you have `object` as return type, there are two > options to avoid a return type error: either return the `$this` object, or > return another object. > > > > > My proposal is to set the instruction `return $this;` as optional for > > non-static class methods with `self` declared as return type. > > > I’d rather have a syntax saying explicitly that you want to return $this, > rather than letting the interpreter guess what you meant. The obvious one > is: > > ```php > public function hit(): $this { $this->counter++; } > ``` > > Here, there is only one possible return value, and therefore the `return` > instruction might be reasonably omitted. >
I like the idea of `$this` as a return type but also strongly believe that the use of `return $this;` should be forbidden, eventually for control flow use of `return;` might be justified. Cheers, Michał Marcin Brzuchalski

joke2k

3 years ago
Thanks for the feedback! On Fri, 23 Dec 2022, 09:33 Claude Pache, <claude.pache@gmail.com> wrote:
> It is very common for fluent class methods to have a verbose `return > $this;` ending in their body. > But If you have declared `self` as return type into a non-static class > method you have only two options to return: > > - the $this object > - another instance of the same class or subclass > > ... in order to avoid a return type error. > > > It is still two options, and it is not clear in general which one to pick. > You could also say that, if you have `object` as return type, there are two > options to avoid a return type error: either return the `$this` object, or > return another object. >
Yes but declaring `self` is more strict than `object`. And talking about the word itself... Declaring to return (your-)`self` but you could return someone-else of the same type as you. But it is ok, it refers to the class name not the instance. just semantic. My proposal is to set the instruction `return $this;` as optional for
> non-static class methods with `self` declared as return type. > > > I’d rather have a syntax saying explicitly that you want to return $this, > rather than letting the interpreter guess what you meant. The obvious one > is: > > ```php > public function hit(): $this { $this->counter++; } > ``` > > Here, there is only one possible return value, and therefore the `return` > instruction might be reasonably omitted. >
Return `$this` is a valid alternative indeed. It is an explicit subclass of returning `self` which has a default return object, itself.

Claude Pache

3 years ago
> Le 23 déc. 2022 à 13:46, joke2k <joke2k@gmail.com> a écrit : > > On Fri, 23 Dec 2022, 09:33 Claude Pache, <claude.pache@gmail.com <mailto:claude.pache@gmail.com>> wrote: >> It is very common for fluent class methods to have a verbose `return >> $this;` ending in their body. >> But If you have declared `self` as return type into a non-static class >> method you have only two options to return: >> >> - the $this object >> - another instance of the same class or subclass >> >> ... in order to avoid a return type error. > > It is still two options, and it is not clear in general which one to pick. You could also say that, if you have `object` as return type, there are two options to avoid a return type error: either return the `$this` object, or return another object. > > Yes but declaring `self` is more strict than `object`. > And talking about the word itself... Declaring to return (your-)`self` but you could return someone-else of the same type as you. > But it is ok, it refers to the class name not the instance. just semantic. >
It is not about being less or more restricted, it is about being plainly ambiguous. ```php class Point { public function __construct( protected float $x , protected float $y ) { } public function withY(float $y): static { $newPoint = clone $this; $newPoint->y = $y; // oops, forgot “return $newPoint;” } } ``` With implicit behaviours (at least when there is more than one option), such sort of bugs become less apparent at runtime. Therefore, implicit behaviour ought to be avoided if possible. —Claude

Rowan Collins

3 years ago
On 23 December 2022 13:29:07 GMT, Claude Pache <claude.pache@gmail.com> wrote:
>> Yes but declaring `self` is more strict than `object`. >> And talking about the word itself... Declaring to return (your-)`self` but you could return someone-else of the same type as you. >> But it is ok, it refers to the class name not the instance. just semantic. >> > > >It is not about being less or more restricted, it is about being plainly ambiguous.
Another big advantage of "return $this" is that it can't affect any existing code. Granted, a function marked :self or :static which currently fails to return would be a runtime error, but changing that error into an implicit return $this could be very dangerous. Regards,
-- Rowan Tommins [IMSoP]

Pierre Joye

3 years ago
On Fri, Dec 23, 2022, 7:46 PM joke2k <joke2k@gmail.com> wrote:
> Thanks for the feedback! > > On Fri, 23 Dec 2022, 09:33 Claude Pache, <claude.pache@gmail.com> wrote: > > > It is very common for fluent class methods to have a verbose `return > > $this;` ending in their body. > > But If you have declared `self` as return type into a non-static class > > method you have only two options to return: > > > > - the $this object > > - another instance of the same class or subclass > > > > ... in order to avoid a return type error. > > > > > > It is still two options, and it is not clear in general which one to > pick. > > You could also say that, if you have `object` as return type, there are > two > > options to avoid a return type error: either return the `$this` object, > or > > return another object. > > > > Yes but declaring `self` is more strict than `object`. > And talking about the word itself... Declaring to return (your-)`self` but > you could return someone-else of the same type as you. > But it is ok, it refers to the class name not the instance. just semantic. >
I would rather endure it returns the used instance and not another one with a compatible interface. Not doing do is actually confusing to me, as per the meaning of self. . Or maybe, if the goal is to ease declaration of fluent interfaces (methods chaining), declaring a class fluent (annotation?) would achieve the same with ambiguous names?

Robert Landers

3 years ago
On 12/23/22, joke2k <joke2k@gmail.com> wrote:
> Hi folks, > > What do you think about having a method which returns the class instance > `$this` by default only IF its return type is set as `self`? > > It is very common for fluent class methods to have a verbose `return > $this;` ending in their body. > But If you have declared `self` as return type into a non-static class > method you have only two options to return: > > - the $this object > - another instance of the same class or subclass > > ... in order to avoid a return type error. > > My proposal is to set the instruction `return $this;` as optional for > non-static class methods with `self` declared as return type. > > Example: > ``` > class Counter { > > public function __construct(private int $counter = 0) {} > > public function hit(): self { $this->counter++; } > public function print(): self { echo $this->counter; } > > public function split(): self { return new self($this->counter); } > > } > > $main = (new Counter)->hit()->hit()->hit()->print() > // 3 > $sub = $main->split()->hit()->print() > // 4 > ``` > > Thank you for reading my proposal, > please let me know if you like it or if there are any issues with this. > > Regards, > > Daniele >
As someone who used Scala for a number of years, I’d be very much against this idea. Scala automatically returns the last line of any function and we found it fairly difficult to maintain once the project got fairly large and ended up switching to explicit returns. Mostly we found it too easy to return the wrong thing. In all fairness, I guess you technically don’t have to use it if you don’t want to (you can use explicit returns), but IMHO, using this would greatly affect readability. Every function you read that doesn’t have a return, you’d have to check if the return type is self/static and verify it is void.
-- Robert Landers Software Engineer Utrecht NL

Ilija Tovilo

3 years ago
Hi Daniele On Fri, Dec 23, 2022 at 1:09 AM joke2k <joke2k@gmail.com> wrote:
> > Hi folks, > > What do you think about having a method which returns the class instance > `$this` by default only IF its return type is set as `self`? > > It is very common for fluent class methods to have a verbose `return > $this;` ending in their body.
Instead of adding special syntax to make writing fluent accessors easier, I wonder if something akin to Dart's cascade operator would be a better approach. https://dart.dev/guides/language/language-tour#cascade-notation $foo ..setBar('bar') ..setBaz('baz'); The syntax is just copied from Dart, there's probably a better fit for PHP. .. would invoke a method call but discard the return value, evaluating to the lhs of the method call instead. With an operator solution one can use fluent method calls on APIs that aren't specifically designed for it when desired, accessors can become leaner as return $this is no longer necessary, and it becomes obvious at call-site that the chained methods are called on the same object. I'm not sure about syntax or the fact that Dart allows property assignments in combination with .. as that makes the syntax ambiguous (or whitespace sensitive), but that wouldn't be necessary for what you're proposing. Example of the ambiguity: $foo ..bar = $bar ..baz() // Could be parsed as $foo..(bar = $bar)..baz() $foo..bar = ($bar..baz()) An alternative might be a C# style syntax which would make property assignments unambiguous. $foo { setBar('bar'), baz = 'baz', } But this is also longer and less readable (to me at least). Anyway, just my unrefined thoughts. I would not support implicit `return $this` for self or static. At the very least, the return type should be $this (which is essentially a sub-type of static) but that too doesn't seem like an elegant solution to me. Ilija

Stephen Reay

3 years ago
> On 25 Dec 2022, at 12:59, Ilija Tovilo <tovilo.ilija@gmail.com> wrote: > > Hi Daniele > >> On Fri, Dec 23, 2022 at 1:09 AM joke2k <joke2k@gmail.com> wrote: >> >> Hi folks, >> >> What do you think about having a method which returns the class instance >> `$this` by default only IF its return type is set as `self`? >> >> It is very common for fluent class methods to have a verbose `return >> $this;` ending in their body. > > Instead of adding special syntax to make writing fluent accessors > easier, I wonder if something akin to Dart's cascade operator would be > a better approach. > > https://dart.dev/guides/language/language-tour#cascade-notation > > $foo > ..setBar('bar') > ..setBaz('baz'); > > The syntax is just copied from Dart, there's probably a better fit for > PHP. .. would invoke a method call but discard the return value, > evaluating to the lhs of the method call instead. > > With an operator solution one can use fluent method calls on APIs that > aren't specifically designed for it when desired, accessors can become > leaner as return $this is no longer necessary, and it becomes obvious > at call-site that the chained methods are called on the same object. > > I'm not sure about syntax or the fact that Dart allows property > assignments in combination with .. as that makes the syntax ambiguous > (or whitespace sensitive), but that wouldn't be necessary for what > you're proposing. > > Example of the ambiguity: > > $foo > ..bar = $bar > ..baz() > // Could be parsed as > $foo..(bar = $bar)..baz() > $foo..bar = ($bar..baz()) > > An alternative might be a C# style syntax which would make property > assignments unambiguous. > > $foo { > setBar('bar'), > baz = 'baz', > } > > But this is also longer and less readable (to me at least). > > Anyway, just my unrefined thoughts. I would not support implicit > `return $this` for self or static. At the very least, the return type > should be $this (which is essentially a sub-type of static) but that > too doesn't seem like an elegant solution to me. > > Ilija > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
Out of all the ideas discussed here the only one that doesn’t seem like it lead to confusion or unexpected behaviour to me is the c# style statement which at the surface seems quite similar to the now-deprecated JS “with” statement. Cheers Stephen