Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119068 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 78349 invoked from network); 1 Dec 2022 01:54:36 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 1 Dec 2022 01:54:36 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id BA698180339 for ; Wed, 30 Nov 2022 17:54:35 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS17378 206.123.64.0/18 X-Spam-Virus: No X-Envelope-From: Received: from mail1.25mail.st (mail1.25mail.st [206.123.115.54]) (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 ; Wed, 30 Nov 2022 17:54:35 -0800 (PST) Received: from smtpclient.apple (unknown [49.48.240.15]) by mail1.25mail.st (Postfix) with ESMTPSA id B78CE605DA; Thu, 1 Dec 2022 01:54:29 +0000 (UTC) Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.120.41.1.1\)) Date: Thu, 1 Dec 2022 08:54:26 +0700 References: <0854b030-c51c-4c1b-a7dd-22835a1e5da9@app.fastmail.com> <831b9906-dc0c-420c-b22f-8a0cc8a1ad64@app.fastmail.com> <434BDABD-8551-46C8-98EC-8CA87952AE25@gmail.com> <29f2a6a5-08f7-4abb-965f-56bb1cc49565@app.fastmail.com> To: Larry Garfield , php internals In-Reply-To: Message-ID: X-Mailer: Apple Mail (2.3696.120.41.1.1) Subject: Re: [PHP-DEV] [RFC] Asymmetric Visibility, with readonly From: php-lists@koalephant.com (Stephen Reay) > On 1 Dec 2022, at 08:38, Stephen Reay = wrote: >=20 >=20 >=20 >> On 30 Nov 2022, at 22:09, Larry Garfield = wrote: >>=20 >> On Tue, Nov 29, 2022, at 11:25 PM, Stephen Reay wrote: >>=20 >>> Hi Larry, >>>=20 >>> Thank you for clarifying the setter behaviour in more explicit = terms,=20 >>> but I have to say I=E2=80=99m quite disappointed in this continued = =E2=80=9Cuse the=20 >>> logic of readonly to apply to something that is explicitly not=20 >>> readonly=E2=80=9D - this is even more stark now that you=E2=80=99ve = explicitly made=20 >>> them mutually exclusive behaviours. >>>=20 >>> I=E2=80=99m generally very in favour of maintaining consistency, but = this seems=20 >>> like it=E2=80=99s using technical consistency as an excuse to = justify=20 >>> unintuitive behaviour that breaks consistency in another, much more=20= >>> obvious way. >>>=20 >>>=20 >>> Can you explain why it makes more sense to maintain consistency with=20= >>> =E2=80=9Creadonly=E2=80=9D than it does to maintain consistency with = the existing=20 >>> =E2=80=9C__set()=E2=80=9D behaviour for properties, particularly now = that you=E2=80=99ve=20 >>> indicated these features (asymmetric visibility and readonly) are=20 >>> mutually exclusive?=20 >>>=20 >>> While it=E2=80=99s stated multiple times that =E2=80=9Creadonly=E2=80=9D= introduced a limited=20 >>> form of asymmetric visibility, and thus this is a continuation, in=20= >>> terms of intuitiveness, the existing __set() rules are very easy to=20= >>> comprehend even with readonly: >>>=20 >>> - if the property is declared as public, __set() is never called; if=20= >>> it=E2=80=99s declared as protected, __set is called when the = property is=20 >>> accessed from outside that class or it=E2=80=99s hierarchy. Yes, I = know that=20 >>> readonly imposes an implicit visibility difference - but that is=20 >>> essentially an implementation detail, from the point of view of the=20= >>> userland developer, it=E2=80=99s not a clear statement of intended = behaviour on=20 >>> their part, expressed through the code as written. >>>=20 >>> For example, with `public readonly int $foo` it=E2=80=99s quite = obvious why=20 >>> __set() isn=E2=80=99t called, using the exiting well-understood = logic: it=E2=80=99s a=20 >>> public property. PHP applies a kind of asymmetric visibility to the=20= >>> property behind the scenes, but that isn=E2=80=99t what the = developer declared,=20 >>> it=E2=80=99s the implementation. This behaviour matches that of = regular,=20 >>> non-readonly fields: when the field is declared public (or has = implicit=20 >>> public visibility) __set() is never called. >>>=20 >>> If we make that field protected, __set() will be called when the=20 >>> property is written to from outside the class, regardless of whether=20= >>> it=E2=80=99s readonly or not. >>>=20 >>>=20 >>> What you=E2=80=99re proposing changes that, in a way that is = completely=20 >>> unintuitive: when attempting to *write* data to a property that is=20= >>> marked as protected(set), the __set() method will not be called. >>>=20 >>>=20 >>> So please, can you explain to me why consistency with an = implementation=20 >>> detail of readonly properties is more important than consistency = with=20 >>> declared developer intention for regular properties via the magic=20 >>> setter method? >>=20 >> There's a couple of reasons. >>=20 >> One, and arguably the most important, readonly and aviz being = incompatible is, hopefully, a temporary situation. There's some fiddly = bits to work out design-wise, and based on earlier comments in the = thread we're going to punt on that for now to avoid that dragging down = the whole RFC. I believe we absolutely should allow them together in = the future (maybe in a later 8.3 RFC, maybe a future version, TBD), = which means ensuring, now, that they are compatible in the future. This = approach involves the fewest future BC breaks. >>=20 >> Second, I wouldn't call the current behavior of readonly a mere = implementation detail. It's weird and unexpected, I'd agree, but only = as a side effect of previous design decisions, some of which are even = older than readonly. But it's an observed behavior that code can rely = on, and in some cases does. For example: >>=20 >> = https://peakd.com/hive-168588/@crell/php-tricks-lazy-public-readonly-prope= rties >>=20 >> The "unset a declared property to force it through __get once" is a = trick that some ORMs use extensively. readonly just inherited that, = leading to the current behavior: __set depends on the write/set = visibility of the property and its settedness. This RFC doesn't change = anything there. =20 >>=20 >> The alternative would be to have __set called always for a = non-public-set property. However, that is a place for bugs, as you then = can't not have a back-door way to publicly set a property even if it's = declared private(set). (Or, you have to be very careful in your __set = to avoid it.) That is both inconsistent with the language today, and = error prone. >>=20 >> Finally, we're planning to work in the near-future on property hooks = (aka property accessors), which would allow per-property custom set = routines. That would largely remove the issue entirely, as the use of = __set would go way down and you'd basically never have to use it with a = declared property, fancy tricks or no, so this issue would never come up = at all. >>=20 >> --Larry Garfield >>=20 >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: https://www.php.net/unsub.php >=20 > Hi Larry, >=20 >=20 > I think there must be some confusion somewhere, based on some of your = comments. >=20 > I=E2=80=99m not suggesting that the =E2=80=9Cunset to force a = **public** property to go through getter/setter methods=E2=80=9D logic = should be specifically different. >=20 > I=E2=80=99m suggesting that when the decision is made to call __set or = not, the properties **set** visibility is what should be considered, not = it=E2=80=99s **get** visibility. >=20 > Your own comment even describes this behaviour: "leading to the = current behavior: __set depends on the write/set visibility of the = property" >=20 > But your RFC says that __set will depend on the **read/get** = visibility of the property. >=20 >=20 >> you then can't not have a back-door way to publicly set a property = even if it's declared private(set). (Or, you have to be very careful in = your __set to avoid it.) That is both inconsistent with the language = today, and error prone. >=20 > If a developer adds a _set() method that can write to a private(set) = property, I would expect that is working exactly as desired, exactly as = it does **now** where it=E2=80=99s just a =E2=80=9Cprotected=E2=80=9D = property. >=20 >=20 >> we're planning to work in the near-future on property hooks >=20 > That=E2=80=99s great, but I don=E2=80=99t think weird unintuitive = behaviour should be added because =E2=80=9Cwell we=E2=80=99re gonna try = and solve this through something else later=E2=80=9D >=20 >=20 >=20 > Cheers >=20 > Stephen=20 >=20 > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >=20 Apologies, I meant =E2=80=9Cwhere it=E2=80=99s just a private = property=E2=80=9D rather than =E2=80=9Cjust a protected property=E2=80=9D = in the second to last sentence.