On Mon, 2 Feb 2026 at 01:20, Rob Landers <[email protected]> wrote:
>
>
>
> On Mon, Feb 2, 2026, at 00:41, Morgan wrote:
>
> 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.
>
>
> Hi Morgan,
>
> From an observability point of view, you lost me when you said return's type 
> is "never".
>
> https://3v4l.org/plpIf#v8.5.0
>
> We can clearly see the type is "null", unless you mean something more 
> abstract?
>
> Are you thinking of return as a function call, so you could write it out like:
>
> return(return($x*2))
>
> I guess in that case, you could conceptually think of its arguments as 
> function that returns what to return? Thus the above is just sugar for:
>
> return function() {
>   return fn() => $x*2;
> }
>
> Which would just collapse down to:
>
> return $x*2;
>
> I think you could handwave it down to that. The removal of the infinite 
> functions is just an optimisation.
>
> — Rob

Hi Rob,

I think `never` as a result of `return` makes complete sense. `never`
indicates something does not result in a value, e.g `throw` or `exit`
where the control flow is given away, `return` as an expression would
do the same thing, it will move a value out of this function scope to
the caller, resulting in `never` within the function. ( the same would
apply if `break` and `continue` are to be made expressions in the
future ).

As for `return` as a function call, i don't think that is needed, once
`return <expr>` is supported as an expression, you would be able to
return `return("foo");` as that is just `return` with the RHS being a
parenthesized expression; the reason i think `return` does not make a
sense as a "function" is because i think function call rules should
not apply to it, e.g what happens if you provide multiple arguments?
Does it throw an `ArgumentCountError`? This is avoidable by making
`return ("a", "b")` a parse error.

Cheers.
Seifeddine.

Reply via email to