Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:128128 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 6B0E91A00BC for ; Fri, 18 Jul 2025 19:43:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1752867697; bh=4EdC4KElInYhbXlxplLp54lC+9gOlX22O1PBW2y2CbU=; h=References:In-Reply-To:Reply-To:From:Date:Subject:To:Cc:From; b=XKYl54rAIalKd1wUHQjBdKtQY32Zhxes/a2AuHU6CGjIlRM3HpeVZXMvYa160tmkI j6WlRN0q8Bgb9wAHI0of07+DtXObHsHslzSTvfzZ6e7oUVE+ZQSAr/tVnnVISkzBht 1aQiCcgpbyyLlLZ31G3ALtCC3bl8srNaWShqp7xQtreBxAss64KZ9xtHOKwJUXB7CT XxeeH2b4EJdq2iP/cAz6kBeyibwsjnq1jsCoGyFMI99bUTG4w2ekiDeJDNAe/EAK8g WgsFHNZ8Y3lZxMv95EPPXwgPlimoCApw8+MlRId0FHUB/nRCnycHd4NC3BEIzc+bKP tzrf/2R8isumw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 28A0B180701 for ; Fri, 18 Jul 2025 19:41:34 +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=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, FREEMAIL_REPLYTO,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-io1-f43.google.com (mail-io1-f43.google.com [209.85.166.43]) (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 ; Fri, 18 Jul 2025 19:41:32 +0000 (UTC) Received: by mail-io1-f43.google.com with SMTP id ca18e2360f4ac-879c737bc03so78550439f.0 for ; Fri, 18 Jul 2025 12:43:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1752867798; x=1753472598; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :reply-to:in-reply-to:references:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=6hHHHoseBEDguStWvJ0NH4ZH7KQHrz1BevlDO1AIVlg=; b=hIAc8Kprey9dV5deA53PthNnrgq2IqZosUImkqJxLm20jKUS9b6ZW5eW41X3hAx0eM 88O2Gx3Kxnv2+5YT1J+oPSAzk0Z9Eubdy1dbK1AxuyT5/Pdz8Emnp87TSCt8HUh7vbM4 wO8/7kVCchm/TvcRshLYh/CH5oxJ5cghXJBZIssXZ+BCX3Itw8Hbk7gAJh991cL5dUat LjcVJhaEnC5SLnclfHH6DbyeHYI6vX/CnEdgFHNgugiZaH3irinScR0SlJyxthwwcRpG XOgBqe+yMKimkdA9tSRaa6VNQZBOtf8pONsvL8gUjdXdR1Jq5/qcBvWTWgr74wdH3FLf cxTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752867798; x=1753472598; h=content-transfer-encoding:cc:to:subject:message-id:date:from :reply-to:in-reply-to:references:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=6hHHHoseBEDguStWvJ0NH4ZH7KQHrz1BevlDO1AIVlg=; b=lmrapSEvtckHRPo4rev0IZ20LLW4ttZ/wfLx9IW6aT+9pP1Uu4FJNOexS+jTqaCCxm PFBhqk2Kb1AO5Qy2KvTbM7xr1NDhKo3nixMWI7uNXb9mCgsuJ5AAie918cqeCntt8IaI pY8QAd0L+rK6gdhwqiQ4V4lvErgnRSziiuvcEi/Ecvf2a81z+QLexGlF6eXMr2mE7gwx 3huJf0RS4AEwliGg0cwHceZkZI5dtuAWTEkLBKA13DdrbPtpDBop9dpUmRCjd2GGbbQx 17FFbYLLR9qLQsz1R7sswQKVKQP19rdBZjz+AqjCFUuEaOn0DrB+rhcCfV6vgNUrU48d b6jQ== X-Forwarded-Encrypted: i=1; AJvYcCU/M/nZs/tc3fLOQsgHVik58EgJ04rASfTYy6Olrhv3T9Xe5eOEauiKD4vC040FGrIeS1Eu8xO352A=@lists.php.net X-Gm-Message-State: AOJu0YzMmWC/IfnR3w6BuRb8xm2uhDYA2VS7Xrrsp5egg+r1qNGzWfM1 y1xcmO6BttqEKVEOlLf23XKQ/GyMVKwOe35YZwgC8HqRiPSPxv2jMTF+DrGkrMvGXkkMc6j/mx1 1NWs/tlCX90SL9oC6w/fWZJDJs1HZSdI= X-Gm-Gg: ASbGncu3Jy68Mwv4YQD587p68CK3i8jxQHoVUDyQlOeOoMs1yuVAe0iOZDxsIa6yUdF EP9iDZrpmpl2xpfUVZ6YMBADFcK2ETek49JJxWUjo88sCyua5h4814y+/QLh6Mz6Ae5b1zyPAYd hnbXitd7R+p+4BhwgVV4f6k75lAUXLFF3SgbU4faM1pL7DWNigWNl+f0XGfzRNLGsydMPoyx39p 6DAdu1kLyrT856U2KCIwZynv7XSxCU/f7Zj+QIc X-Google-Smtp-Source: AGHT+IERu+40HFm9VIVdR1yn+9ea1gsYuXFo79be4cEX+y6yGOFpWSoSL2523SO5dr9jK+46w7n+BxWyAQ6jhxxdcdw= X-Received: by 2002:a05:6e02:174c:b0:3d9:65b6:d4db with SMTP id e9e14a558f8ab-3e282eacd68mr123777615ab.12.1752867798158; Fri, 18 Jul 2025 12:43:18 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <1e8634d7-ac1a-4025-b4e2-1948aabf5251@app.fastmail.com> <09780759-9ddc-45e2-9376-befb8e378775@app.fastmail.com> <0e8eb146-3b1d-4fc2-ad83-77062f2063c9@bastelstu.be> In-Reply-To: Reply-To: erictnorris@gmail.com Date: Fri, 18 Jul 2025 15:43:01 -0400 X-Gm-Features: Ac12FXxYF6ywgFiyTjyxS6Se-n7SAWOj-7ifAjCJRtZDtBiYuF2goyCADVxX-s0 Message-ID: Subject: Re: [PHP-DEV] Re: [RFC] Readonly property hooks To: Nicolas Grekas , Larry Garfield Cc: =?UTF-8?Q?Tim_D=C3=BCsterhus?= , php internals Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: eric.t.norris@gmail.com (Eric Norris) Nick, Larry, On Fri, Jul 18, 2025 at 2:01=E2=80=AFPM Nicolas Grekas wrote: > > > > Le ven. 18 juil. 2025 =C3=A0 18:32, Tim D=C3=BCsterhus = a =C3=A9crit : >> >> Hi >> >> On 7/17/25 18:26, Larry Garfield wrote: >> > Given the lack of consensus both here and in off-list discussions on h= ow to handle get hooks, we have done the following: >> > >> > * Split the RFC into two sections, one for get, one for set. >> > * Expanded and refined the examples for both. The implementation is st= ill the original, however. >> > * Split the vote into two: one for allowing readonly get hooks, one fo= r readonly set hooks. >> > >> > We will start the vote sometime this weekend, most likely, unless some= major feedback appears before then, and let the chips fall where they may. >> >> After working through (most of) the discussion, I've now taken a look at >> the updated RFC. I have the following remarks: >> >> 1. >> >> > It is really =E2=80=9Cwrite-once=E2=80=9D, which is not the same as im= mutable (as shown above). But there's no reason that =E2=80=9Cwrite-once=E2= =80=9D need be incompatible with hooks. >> >> This is a strawman argumentation, as I've outlined in my previous >> emails, calling readonly "write-once" is wrong. It is a reasonable user >> expectation to always get the identical value when reading a value that >> may only be set once. By calling it "write-once" you are trying to shift >> the focus to the write operation, which is totally irrelevant for user >> expectations when interacting with readonly properties. Especially for >> expectations of users that just *use* a class rather than writing one. > > > To my ears, write-once is more accurate than readonly because it sticks t= o the facts of how this behaves. That's very relevant. > Using readonly to suggest immutable is where the arguments for rejecting = this RFC are weak. > readonly doesn't mean immutable, no matter how hard some want it to be... (including a snippet from a separate email from Larry below) > Does readonly refer to the value returned? If so, that's already been br= oken since the beginning because the property can be a mutable object, so t= rusting the data returned to be "the same" is already not safe. It seems to me that the original intent of `readonly` was to mean immutable, and points to a property always equaling itself in the rationale section (https://wiki.php.net/rfc/readonly_properties_v2#rationale): ``` $prop =3D $this->prop; $fn(); // Any code may run here. $prop2 =3D $this->prop; assert($prop =3D=3D=3D $prop2); // Always holds. ``` It even calls out that this *does not* restrict *interior* mutability, which I believe you are using to argue that it doesn't actually mean immutable: "However, readonly properties do not preclude interior mutability. Objects (or resources) stored in readonly properties may still be modified internally." This is exactly how I think about `readonly`. The identity of property won't change, but the object itself might. Now if the object is also a `readonly` class (and recursive for any of those class's properties that are objects), then you *would* truly have an immutability guarantee of both the identity of the object and the object's properties. This is ignoring __get, which I have pointed out elsewhere is worth ignoring, since we can conceivably remove that from readonly classes if we pass `init` hooks. > > >> >> 6. >> >> > So no guarantees are softened by this RFC. >> >> Yes, they are. Unless `__get()` is implemented on a class (which is >> explicitly visible as part of the public API), readonly guarantees the >> immutability of identity. > > > Which is not really relevant when talking about immutability. > What everybody is looking for when using that word is immutable objects. This is not what I am looking for, so I disagree. I would like immutable objects as well, but unless the object itself is a readonly class as noted above, I would not expect it to mean immutable objects. > > >> 7. >> >> > While that is an interesting idea that has been floated a few times, i= t has enough complexities and edge cases of its own to address that we feel= it is out of scope. >> >> While it certainly is your right as the RFC authors to consider certain >> things out of scope for an RFC, I strongly oppose the notion of shipping >> something that is strictly inferior and comes with obvious semantic >> issues due to perceived complexity of another solution and then >> following up with the proper solution that has already been identified. >> As I've outlined in my previous emails, I found defining semantics for >> an 'init' hook straight-forward when looking at how PHP works as of toda= y. >> >> 8. >> >> > However, this RFC is in no way incompatible with adding an init hook i= n the future should it be proposed. >> >> This is true, but as I've mentioned before, an 'init' hook would enable >> the same use cases without bringing along issues. So it really should be >> "one of them, but not both" (with "one of them" being the init hook). >> >> -------- >> >> After reading through the discussion, it seems the only argument against >> the 'init' hook is perceived complexity. It is not at all clear to me >> why this means that we must now rush something with clear issues into >> PHP 8.5. > > > I'd understand the arguments you're pushing for if readonly were appropri= ate to build immutable objects. Yet that's not the case, so such reasoning = is built on sand I'm sorry... > > To me the RFC enables useful capabilities that authors are going to need.= Or find workarounds for. Which means more ugliness to come... I am failing to understand what capabilities are not going to be addressed by an `init` hook, which some of us (if I'm allowed to speak for us) seem to think is the correct approach here. I have noticed in some discussions with my coworkers that it seems that some people think that readonly implies a *contract about writability to consumers of the class*, that is, it implies that consumers of the class can only *read* the value, not write it. I think I could understand why people that think this way would have no problem with `get` hooks, since it still upholds what they think the contract is. I feel, however, that that desired contract is actually achieved by asymmetric visibility, e.g. public(get) protected(set), which I view as orthogonal to readonly. When I point out that asymmetric visibility exists, everyone I've talked to so far agrees that readonly makes more sense as a *contract that the value won't change*. And, as I've pointed out above, I believe that is the intent of the original RFC text for the feature. With this understanding of the contract of readonly, I struggle to understand why an author *who wants to use readonly* would need `get` hook capabilities and not in fact `init` hook capabilities. If they needed generic `get` hook capabilities for a property (and not just lazy loading), then my position is that *they don't actually want readonly*.