> On Aug 14, 2021, at 10:40 AM, Jordan LeDoux <jordan.led...@gmail.com> wrote:
> 
> Never is treated as the bottom type for the purpose of Liskov substitution
> already with its use as a return type. The exception to this in its use as
> a return type is that it isn't treated as the union identity in the return
> type. However, for LSP never is the bottom type when it comes to return
> values. It would, in my mind, be highly inconsistent to have a different
> bottom type for return values than for arguments, so personally I am very
> against using a term other than never. As mentioned in the doc, I wasn't
> able to find a single existing language that has multiple bottom types. If
> anyone is able to provide an example of this, I would appreciate it.

Reading through all the replies on this topic it seems that the functionality 
for the proposal is less controversial than the keyword chosen to identify it.  

It occurs to me that while `never` is the correct keyword for the bottom type 
given past decisions, maybe choosing to use a bottom type to provide this 
functionality is not an idea choice?

If we approach this use-case requirements from a perspective of "this keyword 
indicates that you must implement in a child" then I think we already have a 
keyword that has appropriate semantics compared with the confusing semantics of 
`never` used for a parameter: `abstract`.

So then instead of `never` we could choose the following:

     interface CollectionInterface
     {
         public function add(abstract $input): self;
     }

`abstract` could also work for return types and property types:

     interface Foo
    {
         public abstract $bar;
         public function baz(): abstract {}
    }

Or am I missing something?  Is there a reason `abstract` would not be a better 
choice than `never`?

================

That said, I do have a rhetorical question to ask, to be pondered by those who 
are better attuned to the ramifications of allowing interfaces to become less 
strict than they already are.

From my career-long understanding of declared interfaces the primary (only?) 
reason to use them is to signal and enforce a guarantee that a specific set of 
signatures are available in an instance of a class that implements the 
interface. But if an interface can be defined as something that can can easily 
change based on the implementor, the guarantee that we could previously depend 
on its signatures will no longer be, well, guaranteed.

My gut feeling tells me that will be a bad direction for us to take with PHP.  
What do other's think?

================

After writing the above it occurred to me the solution to the above problem 
already conceptually exists, too, classes get to use the `abstract` keyword 
when their children need to be required to implement something.

If PHP requires interfaces with parameters defined as type `abstract` (or 
`never` if we must)  then those interfaces should also be required to be 
declared `abstract`:

     abstract interface CollectionInterface
     {
         public function add(abstract $input): self;
     }
     Class IntCollection implements CollectionInterface 
     {
         public function add(int $input): self;
     }

The primary tangible difference between abstract and concrete interfaces would 
be in documentation, reflection, and possible an is_abstract() function so that 
code that needs to ensure an exact specific interface could do so.

The benefit of this approach as it appears to me is that (concrete) interfaces 
can retain their same level of guarantee where abstract interfaces would not be 
required to maintain such a guarantee.  #jmtcw

Thoughts?

-Mike

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to