On Monday, 2 June 2025 at 21:53, Rowan Tommins [IMSoP] <imsop....@rwec.co.uk> 
wrote:

> On 02/06/2025 17:27, Gina P. Banyard wrote:
>
>> 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.
>
> I think if "void" was added now, it would be an attribute, rather than a 
> type. It is in effect the exact opposite of #[\NoDiscard], and distinguishes 
> between these two cases:
>
> interface Foo {
> public function getSomething(): ?Something;
> }
>
> class MyFoo implements Foo {
> public function getSomething(): null {
> // My result is always null, but still meaningful to consumers of the Foo 
> interface
> return null;
> }
>
> #[\DiscardReturn]
> public function doSomething(): null {
> // I have no meaningful information to return; any assignment of my implicit 
> value is a mistake
> }
>
> }

A function that always returns the same value is not meaningful to a consumer, 
the only exception is in a class hierarchy with an overloaded method.
But in that case the consumer expects potential other concrete values, so this 
point is a bit moot IMHO.
In the same way as saving the result of print() is pointless because it always 
returns 1, or a function that always returns true.

> I agree the type hierarchy you describe is weird, but rather than throwing 
> away the functionality completely, I wonder if we can make it more consistent:
>
> - Make "no return type declared" and "mixed" equivalent
> - Make "void" a sub-type of "null", and therefore a sub-type of "mixed"
>
> If I've got that right, this would then be legal:
>
> class
>
> A
>
> {
>
> public
>
> function
>
> foo
>
> (
>
> )
>
> {
>
> }
>
> }
>
> class
>
> B extends A
>
> {
>
> public
>
> function
>
> foo
>
> (
>
> )
>
> : mixed
>
> {
>
> }
>
> }
>
> class
>
> C extends B
>
> {
>
> public
>
> function
>
> foo
>
> (
>
> )
>
> : null
>
> {
>
> }
>
> }
>
> class
>
> D extends C
>
> {
>
> public
>
> function
>
> foo
>
> (
>
> )
>
> : void
>
> {
>
> }
>
> }
>
> class
>
> E extends D
>
> {
>
> public
>
> function
>
> foo
>
> (
>
> ): never
>
> {
>
> }
>
> }
>
> That seems reasonable enough; I may have missed something important, though

Not sure if it is important, but you are missing the case where null takes part 
in a union type.
Your proposed change would also allow the following class hierarchy:

class

A

{

public

function

foo

(

)

{

}

}

class

B extends A

{

public

function

foo

(

)

: mixed

{

}

}

class

C extends B

{

public

function

foo

(

)

: string|int|null

{

}

}

class

D extends C

{

public

function

foo

(

)

: void

{

}

}

class

E extends D

{

public

function

foo

(

): never

{

}

}

But if people think this type hierarchy makes more sense, then sure.
I am not convinced, as I think it is a *good* thing PHP always returns a value 
from a function.
Lying about this just seems pointless and leading to misunderstandings about 
how the language behaves.
Best regards,
Gina P. Banyard

Reply via email to