Re: [VOTE] Void Return Type RFC
| From: | John Bafford | Date: | Fri, 30 Oct 2015 16:32:33 +0000 |
| Subject: | Re: [VOTE] Void Return Type RFC | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 12 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-89018@lists.php.net to get a copy of this message | ||
There are two particular semantic advantages of void functions I’m not sure have been brought up.
A function that always throws an exception can’t have a return value (and checking for one is also
semantically and logically incorrect). Since such a function won’t ever return by normal means,
the caller can't ever receive or inspect a return value.
A class of functions never return. That is, they always do one of
* infinite loop
* exit();
* pcntl_exec() or exit();
* terminate the process (e.g. trigger SIGKILL or other fatal signal to its pid)
* terminate the thread (e.g. pecl pthreads Thread->kill())
* (There isn’t actually a facility for doing a setjmp/longjmp from userspace php, is there?)
* otherwise somehow prevent a return to parent scope
In this case, similar to the function that always throws, testing the return value is an error. The
function *can’t* return, so there should never be anything to test. (And thus, testing its return
value is a semantic error, which also implies a logic error because the caller is making an invalid
assumption).
As an aside: if functions can somehow be annotated as no-return, static analysis tools could even
flag code following said function calls as dead and warn about the existence of unreachable code.
Wether PHP should add a noreturn keyword, or if a docblock annotation of a noreturn property should
be “standardized" is a discussion for another time.
Originally coming from a C background, I’ve always appreciated that PHP functions always had a
return value (even if null), because it allowed writing code such as this:
function method() {
// … preprocess ..
$return = parent::method();
// … postprocess ...
return $return;
}
without needing to know to whether the parent method actually returned anything or not (and working
seamlessly in the case that the parent method changed what it was returning).
Given the above, and the fact that changing types on parent functions are going to force a change to
child functions anyways, potentially the following three cases could be allowed:
function func() : void { return someOtherVoidFunc(); }
function method() : void {
// … preprocess ..
$return = parent::method(); //or possibly, some other void function
// … postprocess ...
return $return;
}
$variableNeverRead = voidFunc();
That is: allow “void” to be a write-only variable type, and trigger an error only if anything
actually attempts to do any sort of operation on its value (as in, you can’t even inspect it to
see if it’s void or not). Attempting to assign into a reference should probably fail immediately.
While I’d kind of like to see that, I’m not really sold on it since if the parent/called
function’s prototype changes, the child/caller is going to have to change anyway (to account for
the types of return values changing), so limiting that change to only the return type and not also
the return itself is a potentially dubious win given the potential technical complexity involved in
implementing this.
Thoughts?
-John
> On Oct 30, 2015, at 04:38, Chris Riley <t.carnage@gmail.com> wrote:
>
> Hi,
>
> I'm still not sure why we are using void as the return type and not null.
> Null matches behaviour, void just adds another keyword without value.
>
> ~C
>
> On 30 October 2015 at 04:33, Rasmus Lerdorf <rasmus@lerdorf.com> wrote:
>
>> On 10/29/2015 08:55 PM, Stanislav Malyshev wrote:
>>> Hi!
>>>
>>>> "void" or "null" as return type would give a 100% guarantee
>>>> that every
>> possible
>>>> implementation of a given interface won't return any random value. Then
>> it would
>>>> make no difference if the returned value is being used or not, as it
>>>> would always
>>>> be null.
>>>>
>>>> So, it obviously solves the problem presented. There's not much to
>> dismiss here.
>>>
>>> That's what I am having issue with. I don't see the case where such
>>> guarantee is useful. If you're not using the return value, why do you
>>> care if it's always null or sometimes null and sometimes baloney
>>> sandwich? If you need always null, you have it: null. You don't need to
>>> use return value of a function for it.
>>
>> I agree with you Stas, but I still voted yes on this RFC as I don't see
>> the harm in having it. It is more of a hint for the compiler/static
>> analyzers for them to spew warnings/errors than it is a useful feature
>> at runtime. Enough people consider it a missing check mark on the
>> feature list for it to be added.
>>
>> -Rasmus
>>
>>