Re: [RFC] Static return type
| From: | Nikita Popov | Date: | Thu, 09 Jan 2020 15:30:30 +0000 |
| Subject: | Re: [RFC] Static return type | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-108067@lists.php.net to get a copy of this message | ||
On Thu, Jan 9, 2020 at 4:06 PM Rowan Tommins <rowan.collins@gmail.com>
wrote:
> On Thu, 9 Jan 2020 at 14:23, Andreas Hennings <andreas@dqxtech.net> wrote:
>
> > > However, $this is not a real type, and it is unclear what the advantage
> > of specifying $this rather than static would be from a type system level
> > perspective.
> >
> > Perhaps not from a "type system level", but from a more broad "enforced
> > contract" level.
> > E.g. IDEs or code inspection tools can warn if a method will not return
> > $this.
> > This also means recursive calls also need to return $this instead of
> > static.
> >
> > class C {
> > function foo(): static {
> > return clone $this;
> > }
> > function bar(): $this {
> > return $this->foo(); // IDE can complain.
> > }
> > }
> >
>
>
> I think there are two different purposes for annotating return types:
>
> 1) Contracts that tell the caller what values they should expect when
> calling the function.
> 2) Constraints on the implementation which don't affect the caller, but
> allow the author to catch certain bugs.
>
> The primary purpose, in my mind, is (1), with (2) generally coming as a
> side-effect: if your contract is to return an int, then tools can warn you
> when you don't.
>
> All concrete types can be seen this way: scalars, classes, and pseudo-types
> like "iterable" are all contracts that calling code can rely on. "self",
> "parent", and "static" fit into that list fine, because they're
> ultimately
> specifying a class name.
>
> The special "void" keyword doesn't actually make sense as a contract given
> PHP's calling convention - as far as the calling code's concerned, it's
> equivalent to "null". So it exists only for purpose (2), constraining the
> implementation for the benefit of the function's author.
>
> $this would fit into the same category - as far as calling code is
> concerned it is equivalent to "static", unless they're doing something very
> specific with object identity. This makes it an odd constraint on
> interfaces, for example - DateTimeInterface exists specifically to have
> mutable and immutable implementations, and a return type of $this would
> explicitly prevent that.
>
> If we add ": $this" alongside ": void", I wonder where that takes us next -
> what other constraints on a function can be expressed using that notation
> which aren't contracts on the value seen by the caller? If we don't want to
> explore that question, should we avoid adding ": $this"?
>
An argument could be made that $this does also specify a certain contract
to the caller: That the API may be used fluently or not without change in
functionality. That is
$foo->setBar();
$foo->setBaz();
must be strictly equivalent to
$foo
->setBar()
->setBaz()
;
The same is not the case for a plain "static" type. In fact, I think that
for all other uses of "static" outside of fluent interfaces, not using the
return value would be a programming error.
But still, this kind of contract is not a type-system contract, and I'm not
sure it's a good idea to mix other types of API contracts into the type
system in this fashion.
Regards,
Nikita