Just piping up in a sort of pre-discussion way to see if there might be
any interest in making "return" an expression - in the same way and for
many (though not all) of the same reasons that "throw" was made an
expression in 8.0.
Both return and throw "end the current execution"; the difference is
that "throw" does it because things went bad, while "return" does it
because things went well and nothing more needs doing.
So, for example:
$result = query('foo') ?? return false;
rather than
if(($result = query('foo')) === null) return false;
or
$split = match($len) {
0 => throw new UnderflowException("Unexpectedly empty"),
1 => return false,
2,3,5,7 => return true,
4,6,8,9 => $this->smol($len),
default => $this->foo($len, $scale)
};
instead of
if($len === 0)
throw new UnderflowException("Unexpectedly empty");
if($len === 1)
return false;
if($len === 2 || $len === 3 || $len === 5 || $len === 7)
return true;
if($len === 4 || $len === 6 || $len === 8 || $len === 9)
$split = $this->smol($len);
else
$split = $this->foo($len, $scale);
.
A return expression works entirely by its side-effects (passing control
and the value of its operand back to the calling scope); its own type is
"never".
The weirdest behaviour I can see at this early stage is the main way it
deviates from "reasons to have throw as an expression":
fn($x) => return $x * 2
would work, but not in the way you'd think it does; it expands out to
function($x) {
return return $x * 2;
}
Which (like "throw throw") is syntactically legal, but the redundant
operator is redundant. Semantically, however, it could be problematic:
The anonymous function's return type is technically "never", since that
is what the type of its return statement's operand is. But that return
statement never(!) completes, because said operand causes the function
to end prematurely, causing the numeric value to be returned instead.
And, of course, a numeric value is not a "never".
What this will do to type declarations I don't know. But checking that
the body of an arrow function is a return expression and at least
notifying the author that it's redundant could be done.
This I guess would also impact ordinary return statements: they are now
expressions that evaluate to "never", and that could have consequences
for how return types and return type declarations are determined in
general...
If necessary, I suppose, the type of a return expression could be that
of its operand - it's just that no-one will ever see it because
execution is always abandoned before then.