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

Reply via email to