Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129976 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 6BD041ADCBD for ; Mon, 2 Feb 2026 08:57:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1770022635; bh=cTnVfd1qv9+ZyK8m7FqtKWQZhUIyYnrR+aPteKrwwQI=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=XqKy7zUhUDh79cSU5IQHjovnw6jow1MVwXNvbqM+tMwWQ/XxdEB3kzV/5CBttME2K BBI+4qzcwHfzr1HMz9+I7Xce1E9OuA6lPkpHvRh6k72feMc0zCOncwE0KgC+vT7a6c OQ8PUT1QsRbVJCKqS50Bf84A/G6Mv/bSbeBmYAKh0WBhHOjMeC13t4Il/LJrD1ZUV+ v3GmloqJ4U3qhuSpQtoMN3x80Hv5eLm+kq6l+u0xfraB/xEO8GqNFnunRwvJWfBSUa GMiAJe00iFoPcpIvNi1G+hKoTB7GByLscrSVQQBQM9j2DqGtgSINNSLe56eeidm+pw YA5d/yChpabXQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 4C61D1801D9 for ; Mon, 2 Feb 2026 08:57:12 +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=ARC_SIGNED,ARC_VALID,BAYES_50, DKIM_SIGNED,DKIM_VALID,DMARC_MISSING,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-ua1-f52.google.com (mail-ua1-f52.google.com [209.85.222.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 2 Feb 2026 08:57:08 +0000 (UTC) Received: by mail-ua1-f52.google.com with SMTP id a1e0cc1a2514c-948a076d6ecso385115241.1 for ; Mon, 02 Feb 2026 00:57:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1770022623; cv=none; d=google.com; s=arc-20240605; b=cCvDCiZF4DDaLLdw2SFOfPjwYNwOIYRI4GZ7X2MIiZDT+B9I5ePIznfUTYIXO9CiEo N5uTANtpDvgqKLrpMHo80w1KrmH1JeIC9hdD+T2zjmkzCn78yMJWPvjBe6PTHZ3sNHDV WruqVjRlR62dC1DMWAT0xYsTnJwoE3KFIScGXAHYS5IXeN6otf15QGp/esn8dcCEiWdd RfuK8nKG+aGKq9CKFregudgYLkAvxf/So/75nn4MZR1dXkDUuFCMbmV9iN7DQ3nSyebV nxpdrkOLfL9u1GKrW2FFaqNChA5aKyC/A5SoG9LNWAF1RSrHE5fP61zYC1/K3iD0+7cC HXBg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=b9KUffkd5rUB8e2JXHbiZbLyyVDltGtlRJfH5giXKhQ=; fh=a2UmS3UPhOQSEgu4f/utmrOFMcvVWR9qKLeZmQUqoNc=; b=LVEIg6SgFjhh2+7lsHcYV5gBgVB1wA+sCRKyihc5jhSj00Nq5QW5DX9q0kPbwS5hoY oJ0PKnkY1N6gscXVZ69yb9XLnkmeZAiRyCAm64sa7kS3dLBuXXMnK+AQIcx/nVyTXVJ4 i9bRWww+E4QCuoTDLamWk+03fE/ul7YNwDxTdVIz2XY3tdlzOo1nYuz51DY99Zwd62FX VLPrz/Xn14jQEyP2Lk88FAFPy7ThFjwaJnFBt0JqcWBknbyMeLgW8d5VnLsvceOHBQkS 11BB+Hkj1knWKhAI4sFFcVUCwCEYJgjHmPmDxNLPDA6GTsxdmPg+BP8RGq95IeGKTh8E n3Yg==; darn=lists.php.net ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=carthage-software.20230601.gappssmtp.com; s=20230601; t=1770022623; x=1770627423; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=b9KUffkd5rUB8e2JXHbiZbLyyVDltGtlRJfH5giXKhQ=; b=1cXvub45AlUmgKAx/+JSWScPNzjijNaXA0M6I0ETtGT2nHo2RnYZ2lJBi/Y5zYsO6s SZnI2fRbgrOyLyqhQt+9Ps9rg1/xQlvKx7p1hhDIHgQuuuN5/Ekjc4tJ7kgkmR11zKEy B2Fp4Ar0Xo5yWit6P2NhYj74+PSsLyaRwspqPgV92bSMxi3XlPDGMIbJEn0pRnhgz5yY 3NA9J7lMRimf7rnTs5toIhVSB5CNzoomVbE5eth8qRImluDwD/lLs4PbXPs1yLlgNJE7 V4Xdb3242S/AUgPuXuc6i5MHT70tA/YhAgZVPIdlJNnshsWAzi+TzJUJfOyEusmNNwfa Rj6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770022623; x=1770627423; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=b9KUffkd5rUB8e2JXHbiZbLyyVDltGtlRJfH5giXKhQ=; b=He+B+QbKK20B8U34gY4BDZPsNsr3p/CWD9VeFHLvaISJRSpGd1MPCTYCo//QcF+Bp2 oE9ONjgmMFMr2Dq3b+pFsTOvXSFvFb5wg08hcJV6kOakrayFz8nCJYO+8SB2O/CgKaeq OO5vtXFlvIIxfUxZCz4JNcLiJ/C82MS36712dfiwXGkn1AQRsa/3K1ZQYqNJXgYMGXDi 7a17kZ5M1kEhc+DkfIrD0gbw+CszyqDhexGp2Y3WzXoqcU5yylJ3dYuAS7uOE2lbrRjk v2J1occJU5O9NdshHO3kbm4V+p/cYIMn1UFp/XayImCuHawTtSI127N7pcf5eyFuOHBx 9Cnw== X-Gm-Message-State: AOJu0YxJc2AZSryWaStl51vyEljD2/LFTOvnBXPaBRKwrgRksZfGQQR9 6jJkoJWge24sXp614e2mvAhaHjwkteUTiyfICbcfYpvx9HFKrGBPzn9x8syI2Kz2jIfBK9IasQS TVf9Wm939ENoLExQNdLjeeibhl+3+0vvWqkLcOx96tG5jwEwJeBMd9EY= X-Gm-Gg: AZuq6aIcnJ/kpEHNGOUmXW5Ir2NKyU1MEmUOQ1UUq3XWfwhQjUpe1I4Qwv5jF7rYU46 86X7BpX1q6JtAqDwRZOLS4YM1HRIcIdQrBYyYmUCGl8+y45lQTmWyp2vtyYIhznRDfYhLyT0cgD tTUhu7DkmFZx4DOKRhLlOxlNVtOl1Q3p8PkUOTV5ngvGLpkZKnKdoZYiwG3qYHE9uUBoHnujtNZ /bm/eMRrMiR6btZGNCavXihfhWxHWzAf7SGvsnWa+QRU3Xnpf4niphgkX9Ws/s0P0AeFOTmVb9k 3V/Y6Bo= X-Received: by 2002:a05:6102:44d5:10b0:5f8:e3a9:4135 with SMTP id ada2fe7eead31-5f8e3a9515cmr2427324137.11.1770022623014; Mon, 02 Feb 2026 00:57:03 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Mon, 2 Feb 2026 09:56:52 +0100 X-Gm-Features: AZwV_Qi9OM4LWMyjgYEPeM4kj81ceoIlFGKbzupyelXCT1x6il2tBSWLk23INqs Message-ID: Subject: Re: [PHP-DEV] Return expression To: Rob Landers Cc: internals@lists.php.net Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: azjezz@carthage.software (Seifeddine Gmati) On Mon, 2 Feb 2026 at 01:20, Rob Landers 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 =3D query('foo') ?? return false; > > rather than > > if(($result =3D query('foo')) =3D=3D=3D null) return false; > > > or > > $split =3D match($len) { > 0 =3D> throw new UnderflowException("Unexpectedly empty"), > 1 =3D> return false, > 2,3,5,7 =3D> return true, > 4,6,8,9 =3D> $this->smol($len), > default =3D> $this->foo($len, $scale) > }; > > > instead of > > if($len =3D=3D=3D 0) > throw new UnderflowException("Unexpectedly empty"); > if($len =3D=3D=3D 1) > return false; > if($len =3D=3D=3D 2 || $len =3D=3D=3D 3 || $len =3D=3D=3D 5 || $len =3D= =3D=3D 7) > return true; > if($len =3D=3D=3D 4 || $len =3D=3D=3D 6 || $len =3D=3D=3D 8 || $len =3D= =3D=3D 9) > $split =3D $this->smol($len); > else > $split =3D $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) =3D> 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 t= ype is "never". > > https://3v4l.org/plpIf#v8.5.0 > > We can clearly see the type is "null", unless you mean something more abs= tract? > > 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 fu= nction that returns what to return? Thus the above is just sugar for: > > return function() { > return fn() =3D> $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 f= unctions is just an optimisation. > > =E2=80=94 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 ` 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.