Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129972 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 441E51A00BC for ; Sun, 1 Feb 2026 23:42:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1769989326; bh=StTkeo24LKE7ZVJX5osAVIDuYwujUCUQ2igqX1FjOKI=; h=Date:From:Subject:To:From; b=QrRWTtV40vUeAJ1phctllObeA2ByClCT1u42wBd3/E4cz5HzQ4fND+FtYpICagpZf O1ABsABoBblCk+lxY659vg5eoNsVcfgEckf0O/hIMpVNGd4zlP16QYLmebyJq8SlLm HhzsuK2SdaHoh/K9eWLxVP8NTUkqu16BKUVok4fBeO5gVkE2Rct/mVlb/o0MfRjaz0 +qD5jz+ND2MF0gcwpfRyaAV202deWea5qwBogwlTQ2LS9/YYSD3mTP1q5qUs3PjGXW FHE7mcJ9KHcLDL+LxyI2yflggjipGlIGb0yjhBYN1T23yltBjE7ojmmkuBdMn6S/rl PgXrDQt8JB7Ow== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 56803180069 for ; Sun, 1 Feb 2026 23:42:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50,DMARC_MISSING, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from franklin.smtp.mailx.hosts.net.nz (franklin.smtp.mailx.hosts.net.nz [43.245.52.180]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 1 Feb 2026 23:42:02 +0000 (UTC) Received: from 122-57-27-239-adsl.sparkbb.co.nz ([122.57.27.239] helo=[192.168.1.67]) by franklin.smtp.mailx.hosts.net.nz with esmtpsa authed as varteg.nz (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_128_GCM:128) (Exim 4.96) (envelope-from ) id 1vmh4k-006fXh-0W for internals@lists.php.net; Mon, 02 Feb 2026 12:41:54 +1300 Message-ID: Date: Mon, 2 Feb 2026 12:41:46 +1300 Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: [PHP-DEV] Return expression To: PHP internals Content-Language: en-GB Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Hosts-DKIM-Check: none From: weedpacket@varteg.nz (Morgan) 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.