Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:114741 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 98398 invoked from network); 5 Jun 2021 16:37:34 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 5 Jun 2021 16:37:34 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 9FA691804BE for ; Sat, 5 Jun 2021 09:51:37 -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=-0.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS,SPF_NONE,URIBL_SBL,URIBL_SBL_A autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sat, 5 Jun 2021 09:51:37 -0700 (PDT) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id 50D2A152A for ; Sat, 5 Jun 2021 12:51:35 -0400 (EDT) Received: from imap43 ([10.202.2.93]) by compute1.internal (MEProxy); Sat, 05 Jun 2021 12:51:35 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=7BV1Kt K4BFC9hYHPltREbaxPyDzFja8b/aC1Zc6JD5A=; b=EexiMk6plcxzvPsP/Wz1rQ Ic0cqaRKoqThOBXt4h80yVG3rDSyzgrhZeyQA54hqg7lpsjlu/Cd1pKhTbwsZKq3 lqvK2SK7RUP4UlhajLGYmzXiRaeMEJGFq4VsI3rV+SZbkxdK7Co41LHkWl0eZ4WH fPR09y0QAGePATZKABQ7DS88HMBvffEAeu0H5qTxMlYd8NOj4OYkWFwCUz61/8j+ Of1eo/yBC5i/0mbHVP+vELYMPghu0SOP2TiIiusPe3G3UX1CWomcgnScGEyhs7bX sI7rmEAQM1UJz+R8hdwaDTTAbWHn3/c+4nAqW/rC+fYmxf7Ze82RHAdtRnMjmc0Q == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrfedtfedguddthecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefofgggkfgjfhffhffvufgtsehttdertderredtnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuggftrfgrthhtvghrnhepudejgeeiuddugfetjeduuefhlefhudekvdffvdff leffleduvdffvdegkefhfeetnecuffhomhgrihhnpehphhhprdhnvghtpdhpvggrkhgurd gtohhmnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhep lhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 74723AC0062; Sat, 5 Jun 2021 12:51:34 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.5.0-alpha0-519-g27a961944e-fm-20210531.001-g27a96194 Mime-Version: 1.0 Message-ID: <83a9d0ab-60b8-4939-8be9-bdd6ddeb46c5@www.fastmail.com> In-Reply-To: References: Date: Sat, 05 Jun 2021 11:51:10 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] [RFC] Readonly properties From: larry@garfieldtech.com ("Larry Garfield") On Fri, Jun 4, 2021, at 10:19 AM, Nikita Popov wrote: > Hi internals, > > I'd like to open the discussion on readonly properties: > https://wiki.php.net/rfc/readonly_properties_v2 > > This proposal is similar to the > https://wiki.php.net/rfc/write_once_properties RFC that has been declined > previously. One significant difference is that the new RFC limits the scope > of initializing assignments. I think a key mistake of the previous RFC was > the confusing "write-once" framing, which is both technically correct and > quite irrelevant. > > Please see the rationale section ( > https://wiki.php.net/rfc/readonly_properties_v2#rationale) for how this > proposal relates to other RFCs and alternatives. > > Regards, > Nikita Thank you for the detailed analysis in the rationale section. I am, however, still skeptical of this approach, for a couple of reasons. 1. This does appear to address the "leakage" problem I noted in my earlier analysis around the start of the year, when considering the writeonce proposal[1][2]. That's great to see. 2. It doesn't address the larger question of cloning, however. The answer for now seems "maybe we'll get clone-with at some point", which would be a way around it, but there is no active RFC for that right now. I'm obviously very in favor of RFCs that complement each other to give more than the sum of their parts, but those RFCs need to be at least on the horizon to actually come together. Right now that looks like it won't happen this cycle. Absent clone-with, readonly would be effectively unusable in any evolvable object of any non-trivial complexity. It also wouldn't work with objects that need properties that are not constructor arguments, such as PSR-7 type objects. That's a no in my book. 3. As noted in my previous analysis, even with clone-with, asymmetric visibility results in a nicer syntax when evolving objects that have any complexity to them. (See the examples in [2].) 4. One detail left out of the rationale section is how much of a performance difference there is between readonly and implicit-accessors. It says the latter still has a performance hit, but not how much. How significant is it? If it's tiny, then frankly the biggest argument for readonly goes away, since implicit-accessors gives us 98% the same functionality in a more forward-compatible way without the cloning issues. If it's twice as slow, then having a separate keyword for a common case makes sense. 5. I would have to experiment a bit with hydration, as others have noted, because unconventional object construction mechanisms are a critically important workflow. The RFC even notes in passing that serialization is possibly made complicated. Just how complicated? There's no mention of __deserialize() and how it would interact, but cases like that need to be very clearly handled and documented. 6. I'm OK with the approach to constructor promotion and default values. That seems reasonable in context, especially if combined with New-in-initializers[3], which I am hoping you plan to finish this cycle. :-) 7. Though, it just occurred to me, this may result in issues around optional values. class URL { public function __construct( public readonly string $scheme = 'https', public readonly string $domain = '', public readonly int $port = '443', public readonly string $path = '', ) {} } Now, if you want to hydrate the object externally, you need to ensure those properties are not set by the constructor. However, a promoted value is always set by the constructor; either it has a default or it is required. From previous replies it sounds like the workaround for that is reflection and newWithoutConstructor(), but I'm not sure how I feel about that, because that would also then preclude any *other* logic in the constructor, as that would also get skipped. Perhaps this isn't as big of an issue as I think it is, and if so I'd love to hear why, but it makes me concerned. 8. Although the RFC says it does not preclude accessors or explicit asymmetric visibility in the future, and I absolutely believe that Nikita is genuine about that, I am still concerned that should more robust proposals come forward later, it will be met with "we don't need another still-fancier syntax here, readonly is good enough." It's good to know that C# manages to have both, but that doesn't mean the same logic would apply in PHP, or to PHP voters, specifically. 9. I know that the variance for properties in child classes was a source of discussion, and the end result seems to be that readonly-ness is invariant. However, that precludes having an easy way to have both a mutable and immutable version of a class, easily. (If you wanted to have, say, a read-only class most of the time for safety, but for writing you use an alternate "open" version that can be updated and then persisted to the database.) That's a style I've experimented with on and off for a while and already don't have a great solution to, but it feels like readonly would make that even harder. Again, I'd be very happy to hear alternatives around that. Depending on the answers to the above, I could be convinced of this as a stop gap iff paired with clone-with in the same version. However, on its own I think this is only a half-solution, and I'm not wild about a half-solution for a version or two. That's why I prefer going straight to asymmetric visibility, as that would cover mostly the same use case in a single RFC while still being forward compatible; it would benefit from clone-with, but still be usable without it. [1] https://peakd.com/hive-168588/@crell/object-properties-and-immutability [2] https://peakd.com/hive-168588/@crell/object-properties-part-2-examples [3] https://wiki.php.net/rfc/new_in_initializers --Larry Garfield