On Wed, Jun 4, 2025 at 4:49 PM Bob Weinand <bobw...@hotmail.com> wrote:
> On 4.6.2025 22:39:28, Daniel Scherzer wrote: > > On Wed, Jun 4, 2025 at 1:35 PM Bob Weinand <bobw...@hotmail.com> 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" (= 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" = "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 (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 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.35_and_later. PHP is used to help enforce this. > 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". 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