On Thu, Jan 9, 2020 at 4:06 PM Rowan Tommins <rowan.coll...@gmail.com> wrote:
> On Thu, 9 Jan 2020 at 14:23, Andreas Hennings <andr...@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