rfc:allow-void-variance

This is an old revision of the document!


PHP RFC: Allow void override

Rationale

This RFC proposes to change void 's behavior in class methods, because the current behavior resulted to cause more annoyance than benefit. What is proposed is backward compatible and in accordance with the goals of the previous void RFC.

The intent of void should be simply making clear to the reader that the function does not return anything useful, and that any attempt to use the returned value should be considered an invalid operation.

It shouldn't do more than that, but currently it also denies methods to be overridden with different types in subclasses.

class Foo{
    function method (): void  {}
}
 
class Bar extends Foo{
    function method (): array { return []; } // fails
}
 
class Baz extends Foo{
    function method ()        { return 42; } // also fails
}

This should be allowed, because it is causing discontent among users, and, most importantly, because it achieves nothing at all.

function myFooConsumer (Foo $foo) {
 
   // method() is void, therefore we won't be using its return type
 
   $foo->method();
}

If a Bar object is passed to the function (i.e. myFooConsumer(new Bar())), even if Bar::method() returns an array, it is not breaking the code in myFooConsumer, because the function myFooConsumer has no interest in the return value of method() at all.

Even if it's receiving a Bar object, the function was originally written to be compatible with Foo objects. The method() can return anything, or nothing at all, but myFooConsumer just does not care about it.

For this reason adding a type to subclasses is not an invalid operation, and denying it is a pointless restriction.

Proposal

This RFC proposes to allow void to be changed to any type or mixed in sub classes. The rest of the current behavior of void is preserved.

A void return's inheritance would work exactly like mixed; that is, the following methods follow the very same covariance rules:

class Foo{
    function method1 (): void  {}
    function method2 ()        {}
}
 
class Bar extends Foo{
    function method1 (): array { return []; }
    function method2 (): array { return []; }
}
 
class Baz extends Foo{
    function method1 ()        { return 42; }
    function method2 ()        { return 42; }
}

Except that method1, unlike method2, makes clear that it's not returning anything (but it might do so in subclasses).

void can be overridden to any type including mixed and void itself, but mixed can't be overridden with void like so:

class Foo{
    function method (): void {}
}
 
class Bar extends Foo{
    function method ()       {} // ok
}
 
class Baz extends Bar{
    function method (): void {} // error: can't go back to void
}

This is not technically invalid since mixed includes null, but it certainly feels “not LSP-valid” and it's therefore disallowed by this RFC.

Backward Incompatible Changes

None.

Proposed PHP Versions

7.2.x, 7.3.x, 7.4.x

Voting

2/3 majority will be required.

References

rfc/allow-void-variance.1549249245.txt.gz · Last modified: 2019/02/04 03:00 by wesnetmo