Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:118957 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 96994 invoked from network); 4 Nov 2022 00:01:53 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 4 Nov 2022 00:01:53 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id B0F4D180539 for ; Thu, 3 Nov 2022 17:01:51 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS36483 23.83.208.0/21 X-Spam-Virus: No X-Envelope-From: Received: from quail.birch.relay.mailchannels.net (quail.birch.relay.mailchannels.net [23.83.209.151]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 3 Nov 2022 17:01:50 -0700 (PDT) X-Sender-Id: dreamhost|x-authsender|josh@joshbruce.dev Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 17FA2821770; Fri, 4 Nov 2022 00:01:49 +0000 (UTC) Received: from pdx1-sub0-mail-a221.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 8C68A821819; Fri, 4 Nov 2022 00:01:48 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1667520108; a=rsa-sha256; cv=none; b=ToiHFNq8V+ca4rVV2tP7ZtCHaI59G5csxixE2oDmACKIb7He3UD4wZlRnLMYRnetFctJeM px/e9hMI9KgIJrNYBa5l3MhCPxNbMrkNb0eWmM78vEK4qMOLubL49KI00QaSXET179bTok kbNzwIf29ZgYjt7BSrH6mv0irrv10aGHtxi8Lux0XDNZN1bCnBm2y+LgUrEz0rXlxP10WI h2LAtLQlQLSyn01YjgbNlsspVjTVbUSfs2d9rxNL8dbcQVVIJm+rIiNbDGkOKZh5b9ZZDg u45XWWlQhlq4MOC3QvEK9JeIoxqQxSOOn0Q2GA4ya3AYA72HtCbWJlTPBuduuw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1667520108; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references:dkim-signature; bh=uwY3rS+HLy9ZVsm67N3MFL+qUQzho5lOxa+czz0amyE=; b=aggZUflk8w31XhnmygTyK99P1V1sEOL4dyEUq43RC/NXshTgU7t5wvKTQDE5Pj+rxUnldB 10ADmsiGZd3KI56OsBOmFWmf63O2JOhM/llEde3KK2vdSvw8uagE3pX1ERuW1tvWYMrlqQ LGRh1czrQ+L3SxPPtRkWAW6RJ0HO0SERh+ydE/fuf1BxAUkqJYhSe8Qs/Pq3dbAf0LkZ51 Cn71iWTeR2toSkcRgOL+xkghPoo6DdWTRZi+rt5WG+U4yHn8zbUWsIY0y1hOWZFLTzqScD EOkCAM/K1BleQx58lOpUTa58CsOhp/E9bTu6jSEeidkFTcJ9FPGwcrOWdx4xFA== ARC-Authentication-Results: i=1; rspamd-7f9bbcf788-9f56r; auth=pass smtp.auth=dreamhost smtp.mailfrom=josh@joshbruce.dev X-Sender-Id: dreamhost|x-authsender|josh@joshbruce.dev X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|josh@joshbruce.dev X-MailChannels-Auth-Id: dreamhost X-Blushing-Battle: 564c6d4b318928e4_1667520108861_1853191761 X-MC-Loop-Signature: 1667520108861:280042764 X-MC-Ingress-Time: 1667520108861 Received: from pdx1-sub0-mail-a221.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.123.200.76 (trex/6.7.1); Fri, 04 Nov 2022 00:01:48 +0000 Received: from smtpclient.apple (111.sub-75-244-34.myvzw.com [75.244.34.111]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: josh@joshbruce.dev) by pdx1-sub0-mail-a221.dreamhost.com (Postfix) with ESMTPSA id 4N3LQM5NyPzB3; Thu, 3 Nov 2022 17:01:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=joshbruce.dev; s=dreamhost; t=1667520108; bh=uwY3rS+HLy9ZVsm67N3MFL+qUQzho5lOxa+czz0amyE=; h=From:Content-Type:Subject:Date:Cc:To; b=STDDbThueZG2HivUHhqwgGMoRtzyk9hjHHHYkssMyWjN2jzGuDobU1R9DUzVSHflt d7axvu2IeTWBu4ibZYK0rraw0z5Sflk78CjgmT1YpJPSnCKSzxsdxB+h5YxqfUuTP/ YxpFMU8d4PxiPCTs8rSANiJPq8Vha2rcZpQ1zBLLNNhFKmO2W2dRc7y32/eo9XegRN brsN2SOhWkc2zQ0skttDjEbBkKZ75Rt7DPwSbZIHKVgAGK3rsbcqnbFhpXc9hbOfTM UN1MMYoHOnmzkzBcKOY4jy6YJHSHLOyLuTt5/LFkOJUXe1Eh04QP0Jhr8EI9DEYtgm cpMo8vGtUUpWw== Message-ID: Content-Type: multipart/alternative; boundary="Apple-Mail=_FA076732-25DA-4BFA-B2EE-3E794F108CE7" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.200.110.1.12\)) Date: Thu, 3 Nov 2022 20:01:35 -0400 In-Reply-To: Cc: Marco Pivetta , =?utf-8?Q?Micha=C5=82_Marcin_Brzuchalski?= , php internals To: Claude Pache References: <21C5073D-3F39-49DA-8686-E027AE780793@joshbruce.dev> <1bc7759a-63b8-4b96-bb69-97b50f851307@www.fastmail.com> <94DC0839-E43B-4F3A-9105-8F3CB9D7BBC1@joshbruce.dev> <9AE33306-ED89-4FE4-86A5-89B4EDC81545@gmail.com> <13A9249B-C3B2-46E3-AB50-D46FAA2A301E@joshbruce.dev> X-Mailer: Apple Mail (2.3731.200.110.1.12) Subject: Re: [PHP-DEV] [RFC][Discussion] Objects can be declared falsifiable From: josh@joshbruce.dev (Josh Bruce) --Apple-Mail=_FA076732-25DA-4BFA-B2EE-3E794F108CE7 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > while declaring an object falsifiable changes the semantics of `if = ($obj)`. Got me thinking, appreciate that.=20 In PHP:=20 false =3D=3D empty =3D=3D null=20 (Originally the RFC was geared toward data objects being able to = natively express emptiness when passed to empty() - might be beneficial = for the SimpleXMLElement topic - conversation revealed false and empty = are tightly coupled in PHP and the preference was to declare false = instead of empty to cover more use cases, including empty().) I=E2=80=99m not sure how much if ($obj) actually changes what we do at a = fundamental level - due to the true/false (null) caveat: > Today, in a common situation where I know that a variable contains = either an object of some type or null [=E2=80=A6] > unless I have carefully read the docs in order to know whether they = have opt into that misfeature, and, if so, what exactly =E2=80=9Cfalsy=E2=80= =9D means for them (invalid?, empty?, zero?). Do you still find yourself reading the docs or debugging to figure out = why the thing became null instead of another, expected type (I do)? Asked in a different way, with or without the RFC, I still need to know = if the implementer has opted in to using null (or empty or false), and = under what circumstances I would receive null (or empty or false), yeah? Default behavior is: if (new MyType($config)) { // do something with not null - true - can=E2=80=99t use object = because unassigned } // code is unreachable because instances always resolve to true unless = an exception occurs during initialization; the guard is somewhat = unnecessary. Given the default behavior, would we consider a static initializer = returning MyType|null or ?MyType to be an anti-pattern = (=E2=80=9Cmisfeature=E2=80=9D), because __construct can=E2=80=99t return = null (or false or anything else really)? We could also throw during initialization; see Stripe: = https://github.com/stripe/stripe-php/blob/9c7e27ab7e30a50853aa23139d581cea= b3b5e619/lib/BaseStripeClient.php#L254 try { $obj =3D new MyType($config); // handle true - able to use $obj } catch ($e) { // handle false - object type we interact with is the error - not null = and not $obj, but still represents false because the unintended occurred } Or we could opt in to returning the instance of the error directly, = without throwing: MyType|MyError - user would still need to guard in = some way - using is_a() possibly - see null objects: = https://en.wikipedia.org/wiki/Null_object_pattern Shifting gears. Consider a situation where there=E2=80=99s a range of true and false = within the object definition; PSR-7 responses due to HTTP status codes: = https://www.php-fig.org/psr/psr-7/ and = https://developer.mozilla.org/en-US/docs/Web/HTTP/Status if ($response->getStatusCode() > 199 and $response->getStatusCode() < = 300) { // do something with =E2=80=9Ctrue=E2=80=9D - which has a range of 100 = possibilities at a granular level, which we could respond to differently = - possible to interact with $response } // do something with =E2=80=9Cfalse=E2=80=9D - which has a range of more = than 100 possibilities at a granular level, which we could respond to = differently - possible to interact with $response We might wrap response to create an isOk() method to move the = conditional logic somewhere within the object itself and make the call = site more readable. If ($response->isOk()) { // do something with =E2=80=9Ctrue=E2=80=9D - still able to interact = with $response } // do something with =E2=80=9Cfalse=E2=80=9D - still able to interact = with $response With the RFC: if (new MyType($config)) { // do something with =E2=80=9Ctrue=E2=80=9D - can=E2=80=99t use MyType = because not assigned } // reachable because possible to resolve to false - if implements = Falsifiable and __toBool can resolve to false - can=E2=80=99t use MyType = because not assigned if ($response =3D new MyType($config)) { // do something with =E2=80=9Ctrue=E2=80=9D - with the option of using = $response } // reachable - can=E2=80=99t use MyType because may not be assigned $response =3D new MyType($config); If ($response) { // do something with =E2=80=9Ctrue=E2=80=9D - with the option of using = $response } // do something with =E2=80=9Cfalse=E2=80=9D - with the option of using = $response Or a host of other possibilities for the conditional guard. They=E2=80=99re all shorthands for the same, high-level concept - does = this thing resolve to true *or* false (null), yeah? Cheers, Josh ps.=20 Added open issue of what to do with callable: = https://wiki.php.net/rfc/objects-can-be-falsifiable - specifically in = the context of __invoke() Added invokable RFC to RFC list. > On Nov 3, 2022, at 4:30 AM, Claude Pache = wrote: >=20 >=20 >=20 >> Le 3 nov. 2022 =C3=A0 02:51, Josh Bruce > a =C3=A9crit : >>=20 >> Similar to: >>=20 >> function x(?SomeType $arg): ?SomeOtherType >>=20 >> Instead of: >>=20 >> function x(SomeType|null $arg): SomeType|null >>=20 >> Both are the same thing under the hood. >=20 > The big difference between `?SomeType` shortcut and falsifiable object = feature, is that using `?SomeType` does not change the semantics of = `SomeType|null`, while declaring an object falsifiable changes the = semantics of `if ($obj)`. >=20 >>=20 >> In that same spirit, totally opt-in - not required to use or you can = get there some other way - similar to Marco=E2=80=99s comment around = __toString.=20 >=20 >=20 >=20 > It is opt-in for the implementer of the library, not for the user of = it, as they are not necessarily the same person. >=20 > Today, in a common situation where I know that a variable contains = either an object of some type or null, I routinely write `if ($a)` to = mean `if ($a !=3D=3D null)`. Now, with magic `__toBool()` possibly = implemented by the library=E2=80=99s author, I don=E2=80=99t know what = `if ($a)` means, unless I have carefully read the docs in order to know = whether they have opt into that misfeature, and, if so, what exactly = =E2=80=9Cfalsy=E2=80=9D means for them (invalid?, empty?, zero?). = Ironically, that will incite me to not use anymore the implicit casting = to bool for objects, and to write systematically `if ($a !=3D=3D null)`, = so that both myself and the reader of my code won=E2=80=99t have to look = at the docs in order to understand such simple code. >=20 > =E2=80=94Claude --Apple-Mail=_FA076732-25DA-4BFA-B2EE-3E794F108CE7--