Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122718 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 qa.php.net (Postfix) with ESMTPS id 3DF601A009D for ; Thu, 21 Mar 2024 20:36:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1711053416; bh=6L32gY25+Ycsc5OC3pNLLZjUjqG95X/F8YUFovzwbF0=; h=Date:Subject:To:References:From:In-Reply-To:From; b=DNt+h9tyh1/OmpN4V3b5JSPjOTUpSa4g17zp8x4aOFvW+QRm6XqhAthgD0jYUwOFb SuueaFyEjFkHPVoj4T72B0maDAhXk7xsEQoCBuA0jgPEP1TD155j6Mdto69X+gzlHO ZNonAQkBTVuyEJtWFfTYCFPmM9Gbgas8Oq0wQNY2LTlAqbY6jfd772uem6d11qieZe hugiGvCjmrZ57gOU7TdcZZVZBNljJD45s+JIB9Gz/N0/Djq8e69JY1+DX87D7cxJCK Tucz9Pf4GRkDLzsUb27LbOEF16A0c5CLaz/4Otg6dQLBXlQKYTRUKXmzC+MdVOL8Qq DXa0OFDnLtG5A== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 44ED0180549 for ; Thu, 21 Mar 2024 20:36:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from fhigh8-smtp.messagingengine.com (fhigh8-smtp.messagingengine.com [103.168.172.159]) (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 ; Thu, 21 Mar 2024 20:36:50 +0000 (UTC) Received: from compute6.internal (compute6.nyi.internal [10.202.2.47]) by mailfhigh.nyi.internal (Postfix) with ESMTP id D9754114005D for ; Thu, 21 Mar 2024 16:36:27 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute6.internal (MEProxy); Thu, 21 Mar 2024 16:36:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rwec.co.uk; h=cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1711053387; x=1711139787; bh=7dVuTAuqDG v1/yWWVxkzWPjesRUDYRD4/EQvzIWO9e4=; b=ZRnDudb+P+ILv0sGNmUAEWHsI1 Dm810iZhqvZCLDoIXWGtJ2vI4UL51/ITNmlcxvisBG+P8viGGAZsuRPEm6o5yKoI 34UTHoOavr7uXwLJW0e/iHTqJYDR4MItVPTq6EJOve/wpCUZal96ySZJ7CdbzyeO tRs+iHTEvOr7r6+vfKHlW0ok4No8OPIFsg23AlO1f2KPvsy7q636C1nRlBrC4nTz msCvugNIsgdrHq8nCgt/Aodv9pQ9+4LvLYDpZ/bE5Qp65vVGHkttoHvBbXPbXnPP aopPbhU/kv0s1PlXmLpGni2Hklo5yc6W+S6OxuLmn1WO04JLhl195s1YZXNg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; t=1711053387; x=1711139787; bh=7dVuTAuqDGv1/yWWVxkzWPjesRUD YRD4/EQvzIWO9e4=; b=D4hz0DTklaPbJch0jtI+YoOv0ZgSsBZONopHWDb4Ry9T 6JR7frUttLPVpwz5xiM2t459D8DmUDEPgh/E+6SxQMoYyANxcv2vl9ST1+0NmD8C IViXIR6kMvj6y3XpCly/CtntsbGlxMUw6J4VkqjSjwpnBArHC9Y5Vn5q9FgCJinB sRKC0RXB1Wm/r4LErecbVWJXUYWIVMsX1Tiv0L+8sBiQgUBJNAGhykAsayLkUJqn QGmrtpW+ylmdUOo6GbyYNNQKrP2wwsNINTqbEc65oc2JAhVO5SYb7PuZnToM/wCi b2DHo7Nypoe/o8lS68AfxZQyJ8bae/buRIEi2sHm7g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrleejgdejkecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecunecujfgurheptgfkffggfgfuvfhfhfgjsegrtderre dtvdejnecuhfhrohhmpedftfhofigrnhcuvfhomhhmihhnshculgfkoffuohfrngdfuceo ihhmshhophdrphhhphesrhifvggtrdgtohdruhhkqeenucggtffrrghtthgvrhhnpeehte elieeigfeuudeiueeiffdvveehudeufeekjeeugffffedtiedtgeettdelteenucevlhhu shhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehimhhsohhprdhphh hpsehrfigvtgdrtghordhukh X-ME-Proxy: Feedback-ID: id5114917:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA for ; Thu, 21 Mar 2024 16:36:27 -0400 (EDT) Content-Type: multipart/alternative; boundary="------------s0G8oWXfn8281z09TBLHBJWn" Message-ID: Date: Thu, 21 Mar 2024 20:36:24 +0000 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PHP-DEV] Proposal: AS assertions To: internals@lists.php.net References: <3F78A125-1946-42E2-A4F5-A2B282BE2107@rwec.co.uk> <2d7ec203-6e80-445c-94f4-d29ef58743b1@rwec.co.uk> <40d5c22f-5c06-403d-afc2-84c202277a29@rwec.co.uk> Content-Language: en-GB In-Reply-To: From: imsop.php@rwec.co.uk ("Rowan Tommins [IMSoP]") This is a multi-part message in MIME format. --------------s0G8oWXfn8281z09TBLHBJWn Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 21/03/2024 19:03, Robert Landers wrote: > I suppose we are taking this from different viewpoints, yours appears > to be more of a philosophical one, whereas mine is more of a practical > one. My main concern is consistency; which is partly philosophical, but does have practical impact - the same syntax meaning the same thing in different contexts leads to less user confusion and fewer bugs. But I also think there are real use cases for "error on anything other than either Foo or null" separate from "give me a null for anything other than Foo". > $x = $a as null; > > (or any other value, such as true|false) appears to have no practical > purpose in this particular case. There's plenty of possible pieces of code that have no practical purpose, but that on its own isn't a good reason to make them do something different. "null" as a standalone type (rather than part of a union) is pretty much always pointless, and was forbidden until PHP 8.2. It's now allowed, partly because there are scenarios involving inheritance where it does actually make sense (e.g. narrowing a return type from Foo|null to null); and probably also because it's easier to allow it than forbid it. That's not really what we're talking about anyway, though; we're talking about nullable types, or null in a union type, which are much more frequently used. > Further, reading "$x = > $a as null", as a native English speaker, appears to be the same as > "$x = null". Well, that's a potential problem with the choice of syntax: "$x = $a as int" could easily be mistaken for "cast $a as int", rather than "assert that $a is int". If you spell out "assert that $a is null", or "assert that $a is int|null", it becomes very surprising for 'hello' to do anything other than fail the assertion. > As I mentioned in the beginning, I see this mostly being used when > dealing with mixed types from built-in/library functions, where you > have no idea what the actual type is, but when you write the code, you > have a reasonable expectation of a set of types and you want to throw > if it is unexpected. My argument is that you might have a set of expected types which includes null, *and* want to throw for other, unexpected, values. If "|null" is special-cased to mean "default to null", there's no way to do that. > Right now, the best way to do that is to simply > set a function signature and pass the mixed type to the function to > have the engine do it for you And if you do that, then a value of 'hello' passed to a parameter of type int|null, will throw a TypeError, not give you a null. As I illustrated in my last e-mail, you can even (since PHP 8.2) have a parameter of type null, and get a TypeError for any other value. That may not be useful, but it's entirely logical. > It makes more sense, from a practical programming > point-of-view, to simply return the value given if none of the types > match. This perhaps is a key part of our difference: when I see "int|bool|null", I don't see any "value given", just three built-in types: int, which has a range of values from PHP_INT_MIN to PHP_INT_MAX; bool, which has two possible values "true" and "false"; and null, which has a single possible value "null". So there are 2**64 + 2 + 1 possible values that meet the constraint, and nothing to specify that one of those is my preferred default if given something unexpected. Regards, -- Rowan Tommins [IMSoP] --------------s0G8oWXfn8281z09TBLHBJWn Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit
On 21/03/2024 19:03, Robert Landers wrote:
I suppose we are taking this from different viewpoints, yours appears
to be more of a philosophical one, whereas mine is more of a practical
one.


My main concern is consistency; which is partly philosophical, but does have practical impact - the same syntax meaning the same thing in different contexts leads to less user confusion and fewer bugs.

But I also think there are real use cases for "error on anything other than either Foo or null" separate from "give me a null for anything other than Foo".

$x = $a as null;

(or any other value, such as true|false) appears to have no practical
purpose in this particular case. 


There's plenty of possible pieces of code that have no practical purpose, but that on its own isn't a good reason to make them do something different.

"null" as a standalone type (rather than part of a union) is pretty much always pointless, and was forbidden until PHP 8.2. It's now allowed, partly because there are scenarios involving inheritance where it does actually make sense (e.g. narrowing a return type from Foo|null to null); and probably also because it's easier to allow it than forbid it.


That's not really what we're talking about anyway, though; we're talking about nullable types, or null in a union type, which are much more frequently used.



Further, reading "$x =
$a as null", as a native English speaker, appears to be the same as
"$x = null".


Well, that's a potential problem with the choice of syntax: "$x = $a as int" could easily be mistaken for "cast $a as int", rather than "assert that $a is int".

If you spell out "assert that $a is null", or "assert that $a is int|null", it becomes very surprising for 'hello' to do anything other than fail the assertion.


As I mentioned in the beginning, I see this mostly being used when
dealing with mixed types from built-in/library functions, where you
have no idea what the actual type is, but when you write the code, you
have a reasonable expectation of a set of types and you want to throw
if it is unexpected.


My argument is that you might have a set of expected types which includes null, *and* want to throw for other, unexpected, values. If "|null" is special-cased to mean "default to null", there's no way to do that.


Right now, the best way to do that is to simply
set a function signature and pass the mixed type to the function to
have the engine do it for you


And if you do that, then a value of 'hello' passed to a parameter of type int|null, will throw a TypeError, not give you a null.

As I illustrated in my last e-mail, you can even (since PHP 8.2) have a parameter of type null, and get a TypeError for any other value. That may not be useful, but it's entirely logical.


It makes more sense, from a practical programming
point-of-view, to simply return the value given if none of the types
match.

This perhaps is a key part of our difference: when I see "int|bool|null", I don't see any "value given", just three built-in types: int, which has a range of values from PHP_INT_MIN to PHP_INT_MAX; bool, which has two possible values "true" and "false"; and null, which has a single possible value "null".

So there are 2**64 + 2 + 1 possible values that meet the constraint, and nothing to specify that one of those is my preferred default if given something unexpected.


Regards,

-- 
Rowan Tommins
[IMSoP]
--------------s0G8oWXfn8281z09TBLHBJWn--