Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126720 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 8A7FA1A00BC for ; Tue, 11 Mar 2025 20:01:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1741723146; bh=R1Zzg5M/59AxGXkDPE1NuOrp81KoPA6NCLnxwWVSVA4=; h=References:In-Reply-To:From:Date:Subject:To:From; b=ZtzSWhejEOoXnFvoxBcBa8rxgFwWyLWqoYCs+uDr4M1zbP5ZKyyJaevsaNXyhsE5A OV1QvQS9WUMxri4b+RZJ4Qbo9BOKQKZCJOJth46I4qLUY6MuuTqMBCNdHajeXMk3Sa a2imbs89TxFtKiICWyfqtCm7n1YYXjg/8e2uRN6fMUgcEAvKIWTUeCEFo9o0JEuF5e EpJzwMzKX6+zI9B+9ETH4e70P2oopp8rHvcoeW8+G15Sj4eFRVo5OfzCC7YA0phFYi PQrwwmiiqer+9vTqTuND5hhZ0sKNtMlSe1pHcGlQ6XjlzxinGwTz3UT+CnEXFG19zc 36l64MT+u5uPg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id A666018006A for ; Tue, 11 Mar 2025 19:59:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_05,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-ua1-f43.google.com (mail-ua1-f43.google.com [209.85.222.43]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 11 Mar 2025 19:59:05 +0000 (UTC) Received: by mail-ua1-f43.google.com with SMTP id a1e0cc1a2514c-867129fdb0aso5286337241.1 for ; Tue, 11 Mar 2025 13:01:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1741723298; x=1742328098; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=9w7uX+45O6jRZqXHy6pTj1/VWi37/qMszVKexGauyuY=; b=UueoFelkyQEbLDNA34Dmdnqs/ZJGAVgNq2mCsTM6s9fXMLV5G5HuBYQGS0Ng8qQwuu fxd83kWB/7/mjvTN0ys7Y3//QkN7thPlxN7mheOsTkw/j23QaEMtI7S9P36qjAdur2uX BQP1E2OYAxKZl7IftZpz8nSJkrtj2e8WNcVUQaWou3hw16mvea8kI5Vh9vPzyeU5CJ4r W5sRsGeh4C6yskWAk9n2lepOaBczAUa0aJ0v0/44sxyPk3hnMFx8eAIQ5YejW4SYwNy7 DWg9WpCUh1FKpeZy43GO049Acb/7H5B3Iyjc9g3m5kf+y/uoq9926JwA37CxQPe2q0rK h3Kw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741723298; x=1742328098; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=9w7uX+45O6jRZqXHy6pTj1/VWi37/qMszVKexGauyuY=; b=lwa9hT5C2cFUqbtvHy0jbpzsMbOLtKoocMDRfaMj6FFJcdfHVdpVpXB+VqQZHruaIu ug8D5bdCL06MJ+WIVvj/CbvIXNRRjBlJ61fUwXpWN+D/O///XZAOuF6460p2oYj46PGm QEh0FhEa3NJiMkwoTsJeEaew1e5ROSubVWeFjhWU6IMcQuby3F9NvcUIasE4WpSHsxRo SR/6FsAnFxdHeFGEYiRI+j4+5Nh53LvUjP209CfqlmmxhLrovTfZ3xEZTXFzSzEAIs83 7/7yy3JBNI+znYFkQASUyCoE/+Fc7u1eKqvcQui6s2l4iSHjaAUKfHdHL4rraE2EcTql MFIg== X-Gm-Message-State: AOJu0YzwtGwPcPQDz2b6xadnZIIDTeiw1fTTMtj63zWux5vEKF6ATAZ0 RhQGHpPbwC/7yvjL/bozQaY4Nb72NncDbQXGCI/le5DqZ/yhksjTy0p8oLJ3IHTDWYXcS7hDKLk q9d9BEGKUv3Zy0g7ulg+w9xsoLhoQzLRp X-Gm-Gg: ASbGncsz2Wgf97i2EmrpJmznTMRwq3vGjlxyhwpVVdRvEGp3a+z/HS60btF3mPNRCF+ sIBg4WJHnD8lMPI763U2omBCjVe48YhaR23gNJy+utQHATzYSadO0SBAbFspj6uB7w9JHHBSlmd f5Q/yK/eQwUAtS6AEzatcNLlx5Iw0oR666DnvPEqEtAX21MTIuihT17ggOCA== X-Google-Smtp-Source: AGHT+IETRbdj1Bc5tdL/djotORoUb0Kt5y4rhejSt5qlCyzKzFd6w/mYeulIYkGuEPgJ4sMmsLfkt4flXB4Dn8hppWo= X-Received: by 2002:a05:6102:3710:b0:4bb:9b46:3f71 with SMTP id ada2fe7eead31-4c34d23a493mr4760012137.8.1741723298148; Tue, 11 Mar 2025 13:01:38 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <934418CE-579E-4621-BB7A-5332B87C27B2@zort.net> In-Reply-To: <934418CE-579E-4621-BB7A-5332B87C27B2@zort.net> Date: Tue, 11 Mar 2025 13:00:59 -0700 X-Gm-Features: AQ5f1Jrp4ADu3QM6uPy-Kk30staaQJPqLqY_-IB8isqPGG62YcI4zQKc3YcKuLg Message-ID: Subject: Re: [PHP-DEV] [RFC] [Discussion] Never parameters To: internals@lists.php.net Content-Type: multipart/alternative; boundary="0000000000007bbaa10630168e09" From: daniel.e.scherzer@gmail.com (Daniel Scherzer) --0000000000007bbaa10630168e09 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable [responding to multiple people instead of spamming multiple emails, I hope that is okay] ---- On Mon, Mar 10, 2025 at 12:38=E2=80=AFPM Eugene Sidelnyk wrote: > > Yet, do you think it's reasonable that "never" type should be used rathe= r > than "void"? From what I know, never - is a special type used when functi= on > 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=E2=80=AFPM Ilija Tovilo 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=E2=80=AFPM John Bafford wr= ote: > > 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 produc= e > 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=E2=80=AFPM Rob Landers wr= ote: 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 --0000000000007bbaa10630168e09 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
[responding to multiple people instead of spamming mu= ltiple emails, I hope that is okay]
----

On Mon, Mar 10, 2025 at 12:38=E2=80=AFPM Eugene Sidelnyk <zsidelnik@gmail.com> wrote:

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

Never is a bottom type that means "absolutely no val= ue is possible" - for function returns, since `return;` implicitly mea= ns `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).

=
<= div dir=3D"auto">On the other hand, void is just an indication that functio= n never returns (but doesn't die).

From my understanding, `void` is an indication that a function retu= rns no value, but from a=C2=A0

= In my opinion, it would make more sense to use void parameters.

Also, I remember that in C / C++ la= nguage there's such a concept as "void pointer", - a complete= ly 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 essentiall= y the opposite of what I am trying to accomplish - coming from C/C++, I wou= ld assume a `void` parameter would therefore be the *top* type, allowing an= ything, while `never` is meant to be the *bottom* type, allowing nothing.

----

On Mon, Mar 10, 2025 at 2:= 44=E2=80=AFPM Ilija Tovilo <tovilo.ilija@gmail.com> wrote:=

I would have slightly preferred to investigate ass= ociated types first.
They mostly solve the same problem, except they can= express
relationships between other parameters or return types. For exa= mple:

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 soun= ds interesting, it looks like a lot more work, and since if we introduce as= sociated 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 o= f `never` types now.=C2=A0

----

On Mon, Mar 10, 2025 at 3:11=E2=80=AFPM John Baffo= rd <jbafford@zort.net> wrote= :

I would point out that `never` can be = conceptually represented as a caseless enum. Right now, code like this is v= alid (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 c= annot just widen a caseless-enum-never to just (e.g.) an `int`, it would ne= ed to be `Never|int`. I'll leave further discussion of caseless enums f= or another thread since they are not equivalent from a type-theory perspect= ive.

----

=C2=A0On Mon, M= ar 10, 2025 at 3:59=E2=80=AFPM Rob Landers <rob@bottled.codes> 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 doin= g 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 enu= m can use both. I think odd code like subclasses of `Point` not accepting r= easonable things is something that should be caught by other developers doi= ng code review, not enforced on a language level.

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

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

There= 9;s basically only a gentleman's agreement that a subclass will impleme= nt things in a way that makes sense.

I thin= k that this agreement is present for any method that isn't final, and t= hat doesn't change now - the only difference is that now the PHP compil= er won't get in the way

I would also personally prefer associated types: ...= =C2=A0This at least lets you ensure the "other point" is the same= type in both functions, though personally, I'd rather just have generi= cs.

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 o= f BackedEnum.

----
- Daniel

--0000000000007bbaa10630168e09--