Re: [RFC] [Discussion] Never parameters

From: Date: Tue, 11 Mar 2025 20:00:59 +0000
Subject: Re: [RFC] [Discussion] Never parameters
References: 1 2  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
[responding to multiple people instead of spamming multiple emails, I hope
that is okay]
----

On Mon, Mar 10, 2025 at 12:38 PM Eugene Sidelnyk <[email protected]>
wrote:

>
> Yet, do you think it's reasonable that  "never" type should be used rather
> than "void"? From what I know, never - is a special type used when function
> never returns, and always dies or throws an exception.
>

Never is a bottom type that means "absolutely no value is possible" - for
function returns, since return; implicitly means return null; in terms
of what the caller receives (https://3v4l.org/TNBFE), the only way that
this type is usable is when the function never returns (dies or throws).

On the other hand, void is just an indication that function never returns
> (but doesn't die).
>

From my understanding, void is an indication that a function returns no
value, but from a

>
> In my opinion, it would make more sense to use void parameters.
>
> Also, I remember that in C / C++ language there's such a concept as "void
> pointer", - a completely legitimate structure (likely the same concept as
> here) that could point to address of the data of any type.
>

A void pointer that can point to the address of any type is essentially the
opposite of what I am trying to accomplish - coming from C/C++, I would
assume a void parameter would therefore be the *top* type, allowing
anything, while never is meant to be the *bottom* type, allowing nothing.

----

On Mon, Mar 10, 2025 at 2:44 PM Ilija Tovilo <[email protected]> wrote:

I would have slightly preferred to investigate associated types first.
> They mostly solve the same problem, except they can express
> relationships between other parameters or return types. For example:


I had never heard of associated types before this email thread - google
suggests that they are a feature of rust and swift, neither of which I have
used.
While it certainly sounds interesting, it looks like a lot more work, and
since if we introduce associated types later we can change BackedEnum
without a BC break, I don't think a future possibility of associated types
should stand in the way of never types now.

----

On Mon, Mar 10, 2025 at 3:11 PM John Bafford <[email protected]> wrote:

>
> I would point out that never can be conceptually represented as a
> caseless enum. Right now, code like this is valid (as in, does not produce
> errors, though in practice, it's also not callable):
>

While a caseless enum might represent the concept of a parameter than can
never be valid, subclasses cannot just widen a caseless-enum-never to just
(e.g.) an int, it would need to be Never|int. I'll leave further
discussion of caseless enums for another thread since they are not
equivalent from a type-theory perspective.

----

 On Mon, Mar 10, 2025 at 3:59 PM Rob Landers <[email protected]> wrote:

This looks interesting. I'm not sure that I like "never" as a parameter
> type and while it "technically" doesn't violate LSP, it seems like a
> backdoor to doing just that:


So the initial inspiration for this was the BackedEnum class, where it
isn't a technicality - LSP is violated when the interface allows both
strings and ints, but no actual enum can use both. I think odd code like
subclasses of Point not accepting reasonable things is something that
should be caught by other developers doing code review, not enforced on a
language level.

For example (https://3v4l.org/pTdMg)
```
abstract class Point {
    abstract public function add(Point $other);
    abstract public function subtract(Point $other);
}

class Vector2 extends Point {
    public function add(Point|Banana $other) {
        if (!$other instanceof Banana) {
            throw new TypeError("Point only allowed to prevent compiler
errors");
        }
        // ...rest of the function
    }
    public function subtract(Point|Football $other) {
        if (!$other instanceof Football) {
            throw new TypeError("Point only allowed to prevent compiler
errors");
        }
        // ...rest of the function
    }
}
```

There's basically only a gentleman's agreement that a subclass will
> implement things in a way that makes sense.


I think that this agreement is present for any method that isn't final, and
that doesn't change now - the only difference is that now the PHP compiler
won't get in the way

I would also personally prefer associated types: ... This at least lets you
> ensure the "other point" is the same type in both functions, though
> personally, I'd rather just have generics.


I'd also like to have generics, but that isn't something I can implement
myself. Associated types would be interesting, but I don't think that
associated types would remove the entire use-case for never parameters,
just perhaps the specific example of BackedEnum.

----
- Daniel


Thread (33 messages)

« previous php.internals (#126720) next »