Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127600 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 lists.php.net (Postfix) with ESMTPS id 25A291A00BC for ; Thu, 5 Jun 2025 01:00:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1749085105; bh=hmQMK1Qh369IuTO93suEdPMPiTs6yZnyAL7SUKOJssQ=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=isNSBDre81INUCzANuXlVmkGlWu9r+1K0WWrv5obvh5x6HQzyWVCdQCPgaVamsElI cjYV1NOvGZFBZGLr17COBmHyttcHdGJpaOW4eBoSfJFeScYCJ3wwvQXG/Fr7GLhyu6 SHnmSk0Ggs9O9mRmZvO/VPLNaaEew3DnGjvzEP4euLZPYdWGi3HuVi1uCJO1q0dhWw FQHlj0hunieWEGwnLfNdgHqdHCAH7yvJDa6KVZQ67RJotMjiJ4PBCi7dTch5MvH3kG vl5lUE6OGrCU/vUivhCciSLO3tebeYsta+vwb0tj9NHPbL/3jTb9CFinvuFRMjqcfb zBAKHVLPQ34mw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 5F5FD180056 for ; Thu, 5 Jun 2025 00:58:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.2 required=5.0 tests=BAYES_20,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.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-yb1-f170.google.com (mail-yb1-f170.google.com [209.85.219.170]) (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 ; Thu, 5 Jun 2025 00:58:24 +0000 (UTC) Received: by mail-yb1-f170.google.com with SMTP id 3f1490d57ef6-e733a6ff491so503970276.2 for ; Wed, 04 Jun 2025 18:00:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749085227; x=1749690027; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=8he8+CylnISGnpVi6BGQVDcakp5yVSgJCY2ScewoXUQ=; b=Ixji+WTFKWc+KVOV5+vay6rJtnOoVKitFDLUTNvZm0UKE3xUS8FINgfkfRweGIPGho NJdUrrfV0Hhxhl1+FfLqaVuWxq8BeY31T8GAdXf9NIf3wDuaP5L+9t+T7LMEjyZoKHUv xiRWx87+XUn2xwzhiUVfshtSD92vrXcLh5By5/AgB6M5ukWbs8bInx0qu8PvZAjm2EJE 0y4wCdfynaQO85UDYDzMyOzHxQUA35GTqsulcEokw841csbaPEJIRnhxDalwaw/RlTYs 1N6+u90gU5qHdc7Ciz9gwnZgUgtnODSVegYWJl4kRl/gLuCK3dYuB8jHHQNVUTdbPVZC B/NA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749085227; x=1749690027; h=cc: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=8he8+CylnISGnpVi6BGQVDcakp5yVSgJCY2ScewoXUQ=; b=MTG9xtn8FJV+IPaVvBWU9zyXbo/FLlj0ALZldHjg7mV3t0SrH9HWzRKksKbFOBZN9M iuS0cZLgUY69biLdqcMGb6R5iLYhYhpZYk4PJ4CqMp1aS7g/iCxcG8Yb+KvbfxjUK8NW D2XLxBmIoEYpbeDOhzwZLtGhEzk/KDGnT3mALhYhS8Wr+wyt74Y77X3TqXV+G4NTsTuk CGHr+h0Ff5SZTqR6gyXhqGVM4QBzzy3GwzRBsX1+NsOsdIx4JLH1zrTWeoadgVkw1+n+ cIOl0vuZtejR+OCniGwI/7h6ngBhADHil9CVlm1btbhQBYMbQ1lclhYXOka6XUHTw0xq e21w== X-Forwarded-Encrypted: i=1; AJvYcCWGmhSiSp+u+v0V2saSMMmzpy1MS3dZETfgAAwGSJ9OY9V1XuxUr/c/5pdL2X/njc31otUBVqlanZ0=@lists.php.net X-Gm-Message-State: AOJu0Yy2I4/ylNqAEvz93aZSQU/PEniZToX/bkGxjc0B5UyzLO69SZpa Uh2oovX1QEXIKo6bfaBdZJVBn4BRjZ2s0b99Rt+bHreSCOHDtSX0dTxNZFWaGgH0F0vHURKzUH8 ebtRErFoQRLt3L44sC2+eLvtlPpnxVSYfIBzU X-Gm-Gg: ASbGncu09rK/9w3d5pNE+5iMIVP2D6SMZMtKIrHID1B/68HNHOcctJhIm/nz++i6Y99 aOEZvOy7Da7Rx8B7DSl10gcSWrH2Tj5ejXLyH2kCoztHYRzqL44crx3qCu1U+yNM3517IfOXsO4 s7HcjrFo6V22Zg3fc/VVlO4+nL5e8wR2O3phdONaYmPiQa/bxSaT8A4Tsz+8MOOnXwwDh13LpSi b8= X-Google-Smtp-Source: AGHT+IELT+rcdn3dXDeNr7BhZiZJvFlNOMJQ47QfDHMz21UnmeIehr1JuJXAXhkHi/nH/T99pVBQl0oy5S9fwRtpl9k= X-Received: by 2002:a05:6902:2312:b0:e7d:5e41:a8a4 with SMTP id 3f1490d57ef6-e8179c2e375mr7010868276.16.1749085226713; Wed, 04 Jun 2025 18:00:26 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <6Z2Ysh6MjYp1nyzuB0bTPJc5srObIcMRqt731JaQeXUJk1f_V_Yo2nRn8WvjI7er7pp7pIUE6WYl5pRwvYrtcrd07nCutyAqKPSsZHmrS-Y=@gpb.moe> In-Reply-To: Date: Wed, 4 Jun 2025 17:59:56 -0700 X-Gm-Features: AX0GCFuqbKPeVSt_UVIqmJj00aGRSBtvWDwwNkczUqo2JPOleo2i7ApzZIS-wBQ Message-ID: Subject: Re: [PHP-DEV] [RFC] Transform void into an alias for null To: Bob Weinand Cc: "Gina P. Banyard" , PHP internals Content-Type: multipart/alternative; boundary="0000000000009ec7390636c8a310" From: daniel.e.scherzer@gmail.com (Daniel Scherzer) --0000000000009ec7390636c8a310 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, Jun 4, 2025 at 4:49=E2=80=AFPM Bob Weinand wr= ote: > On 4.6.2025 22:39:28, Daniel Scherzer wrote: > > On Wed, Jun 4, 2025 at 1:35=E2=80=AFPM Bob Weinand = wrote: > >> >> On 4.6.2025 16:54:05, Bob Weinand wrote: >> > On 2.6.2025 18:27:51, Gina P. Banyard wrote: >> >> Hello internals, >> >> >> >> This is the second RFC out of a set of type system related RFCs I >> >> want to propose for PHP 8.5. >> >> >> >> The objective is to fix a weird quirk of PHP's type system, where >> >> void lives in its own type hierarchy. >> >> This is visible mainly in that a lack of return type is not >> >> isomorphic to a function that has a return type of mixed. >> >> >> >> Let me know what you think about it. >> >> >> >> RFC: https://wiki.php.net/rfc/void-as-null >> >> >> >> Best regards, >> >> >> >> Gina P. Banyard >> > >> > I have to agree with other posters here that the distinction between >> > null and void is an useful one. >> > >> > In particular I'd consider the null returned by void to be incidental >> > rather than intentional. I consider the return value of void functions >> > "some arbitrary value". It just happens to be null. >> > Like every function has to return something. But returning null is not >> > an intrinsic property of a void function. It's an extrinsic one. You >> > observe void functions to generally return null. But that null in >> > itself is meaningless. >> > >> > So, my counter-proposal would be allowing covariance with void and >> > allowing everything, including non-nullable types as child type of >> > void functions. >> > I.e. effectively giving void and never the same semantics, except that >> > never also indicates that it never returns. >> > >> > Additionally I'd be in favour of disallowing (e.g. E_WARNING) >> > consuming the return value of _direct_ calls to void functions (with >> > the exception of standalone direct calls in short closures, because >> > consuming that value is intrinsic rather than necessarily >> > intentional). (Disallowing indirect calls would be detrimental for >> > usage as callback.) >> > >> > Bob >> >> >> Clarification: *opposite* semantics to never (which is the bottom type). >> Void would be effectively the top type (only inferior to untyped). >> >> So, it allows child classes to then return a meaningful value when the >> interface was just "void" (=3D no significant return type). As an exampl= e, >> when the interface says "set($val): void", the child class can specify >> "set($val): mixed" and return the old stored value. >> >> Basically, an interface can now say without further clarification "I >> have no real return value" =3D "void", rather than having to say "mixed" >> and then explaining "this is not really mixed, but whatever you want". >> >> (I have seen interface method return values being "upgraded" from void >> to mixed (or just untyped) in the past, just so that a specific child >> class can now return a meaningful value.) >> >> >> Bob >> > > > MediaWiki's hook system (https://www.mediawiki.org/wiki/Manual:Hooks) has > two different kinds of hooks > - those that can be aborted, for one hook handler to say that no other > hook handlers should run > - those that cannot be aborted > > MediaWiki uses `void` return types to help enforce this system, where > hooks that cannot be aborted must have void returns. See > https://www.mediawiki.org/wiki/Manual:Hooks#Hook_handler_return_values. > Making it so that any interface function with a void return can be > implemented by a function returning anything would seem to be a huge B/C > break. If you want to use the top type, why not just use `mixed`? > > -Daniel > > > Hey Daniel, > > where's the BC break? Nothing which worked today will stop working (excep= t > you won't get exceptions in some cases). That's not a BC break. The only > thing which stops working is if it's intentionally used as a guard. > That (intentionally using `void` returns as a guard) is exactly what MediaWiki does. MediaWiki has an interface for each hook, that requires that hooks that cannot abort (return false) must return void; https://www.mediawiki.org/wiki/Manual:Hooks#Handling_hooks_in_MediaWiki_1.3= 5_and_later. PHP is used to help enforce this. > However, in the case of MediaWiki they do actually _care_ about the retur= n > type (and the caller of these hooks will actually check for > null/true/false). So it should be annotated ": null". And not ": void". > Explicit intentions are important. > They probably still use ": void" as to be compatible with PHP 8.1 and > older. ": null" is only supported starting PHP 8.2. I'd assume as they > upgrade their required PHP version (8.1 currently) they'll shift to ": > null". > > So, yeah, the guard will lose its guarding functionality (but we don't > consider that a BC break). > Why is this not considered a BC break? You can consider it a small break, but I think it should be noted in the BC section of the RFC. > > Regarding why not mixed? Because the intention with mixed is that the > value is something meaningful. With void it's meaningless. There's a > semantic distinction (and it forbids returning). And, as proposed, you > could forbid direct calls of void functions giving runtime / static > analysis hints. With void being covariant with respect to child functions > now. > > > Bob > If `void` is a top type indicating a return is meaningless, then callers would have no reason to examine the returned value, and then when subclasses do try to add meaning it might be missed. Am I missing something? How would void be different from "the base implementation happens to always return null, but subclasses can return other things, and the result can be meaningful"? -Daniel --0000000000009ec7390636c8a310 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Wed, Jun 4, 2025 at 4:49=E2=80=AFPM Bo= b Weinand <bobwei9@hotmail.com> wrote:
=20
On 4.6.2025 22:39:28, Daniel Scherzer wrote:
=20

On 4.6.2025 16:54:05, Bob Weinand wrote:
> On 2.6.2025 18:27:51, Gina P. Banyard wrote:
>> Hello internals,
>>
>> This is the second RFC out of a set of type system related RFCs I
>> want to propose for PHP 8.5.
>>
>> The objective is to fix a weird quirk of PHP's typ= e system, where
>> void lives in its own type hierarchy.
>> This is visible mainly in that a lack of return type is not
>> isomorphic to a function that has a return type of mixed.
>>
>> Let me know what you think about it.
>>
>> RFC: https://wiki.php.net/rfc/void-as-null=
>>
>> Best regards,
>>
>> Gina P. Banyard
>
> I have to agree with other posters here that the distinction between
> null and void is an useful one.
>
> In particular I'd consider the null returned by void t= o be incidental
> rather than intentional. I consider the return value of void functions
> "some arbitrary value". It just happens to be nu= ll.
> Like every function has to return something. But returning null is not
> an intrinsic property of a void function. It's an extrinsic one. You
> observe void functions to generally return null. But that null in
> itself is meaningless.
>
> So, my counter-proposal would be allowing covariance with void and
> allowing everything, including non-nullable types as child type of
> void functions.
> I.e. effectively giving void and never the same semantics, except that
> never also indicates that it never returns.
>
> Additionally I'd be in favour of disallowing (e.g. E_WARNING)
> consuming the return value of _direct_ calls to void functions (with
> the exception of standalone direct calls in short closures, because
> consuming that value is intrinsic rather than necessarily
> intentional). (Disallowing indirect calls would be detrimental for
> usage as callback.)
>
> Bob


Clarification: *opposite* semantics to never (which is the bottom type).
Void would be effectively the top type (only inferior to untyped).

So, it allows child classes to then return a meaningful value when the
interface was just "void" (=3D no significant return = type). As an example,
when the interface says "set($val): void", the child = class can specify
"set($val): mixed" and return the old stored value.
Basically, an interface can now say without further clarification "I
have no real return value" =3D "void", rather th= an having to say "mixed"
and then explaining "this is not really mixed, but whateve= r you want".

(I have seen interface method return values being "upgrade= d" from void
to mixed (or just untyped) in the past, just so that a specific child
class can now return a meaningful value.)


Bob


MediaWiki's=C2=A0hook system (https://www.mediawiki.org/w= iki/Manual:Hooks) has two different kinds of hooks
- those that can be aborted, for one hook handler to say that no other hook handlers should run
- those that cannot be aborted

MediaWiki uses `void` return types to help enforce this system, where hooks that cannot be aborted must have void returns. See=C2=A0https://www.mediawi= ki.org/wiki/Manual:Hooks#Hook_handler_return_values. Making it so that any interface function with a void return can be implemented by a function returning anything would seem to be a huge B/C break. If you want to use the top type, why not just use `mixed`?

-Daniel


Hey Daniel,

where's the BC break? Nothing which worked today will stop working (except you won't get exceptions in some cases). That'= ;s not a BC break. The only thing which stops working is if it's intentionally used as a guard.


That (intentionally using `void` returns as a guard) is exactly wha= t MediaWiki does. MediaWiki has an interface for each hook, that requires t= hat hooks that cannot abort (return false) must return void;=C2=A0https://www.mediawiki.org/wiki/Manual:Hooks#Handling_hooks= _in_MediaWiki_1.35_and_later. PHP is used to help enforce this.
=C2=A0

However, in the case of MediaWiki they do actually _care_ about the return type (and the caller of these hooks will actually check for null/true/false). So it should be annotated ": null". A= nd not ": void". Explicit intentions are important.
They probably still use ": void" as to be compatible with P= HP 8.1 and older. ": null" is only supported starting PHP 8.2. I&#= 39;d assume as they upgrade their required PHP version (8.1 currently) they'l= l shift to ": null".

So, yeah, the guard will lose its guarding functionality (but we don't consider that a BC break).


<= /div>

Why is this not considered a BC break? You can con= sider it a small break, but I think it should be noted in the BC section of= the RFC.


Regarding why not mixed? Because the intention with mixed is that the value is something meaningful. With void it's meaningless. There's a semantic distinction (and it forbids returning). And, a= s proposed, you could forbid direct calls of void functions giving runtime / static analysis hints. With void being covariant with respect to child functions now.


Bob


If `void` is a top= type indicating a return is meaningless, then callers would have no reason= to examine the returned value, and then when subclasses do try to add mean= ing it might be missed. Am I missing something? How would void be different= from "the base implementation happens to always return null, but subc= lasses can return other things, and the result can be meaningful"?

-Daniel
=C2=A0
--0000000000009ec7390636c8a310--