Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:118606 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 64359 invoked from network); 11 Sep 2022 15:22:12 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 11 Sep 2022 15:22:12 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 1D1421804AB for ; Sun, 11 Sep 2022 08:22:11 -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.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS19151 66.111.4.0/24 X-Spam-Virus: No X-Envelope-From: Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 11 Sep 2022 08:22:10 -0700 (PDT) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id D23575C00FB for ; Sun, 11 Sep 2022 11:22:09 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute1.internal (MEProxy); Sun, 11 Sep 2022 11:22:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm2; t=1662909729; x= 1662996129; bh=7+iC5s8FgSKUF9eNq0b5LM0BDZdXyuoyNj2kOm272bE=; b=s kLbAW3uII61du+4m7x9jozrnqL47DUhbDycRp8VVL8T1xYYbIPNcCaAiN+vZhurY V2sAsbWrRr1piU0kuxpHRwNXgQywVWrUvnh+OCrQTQ15YBSxK2U20N0+aDlROKxL SHx41n3Gqj1Fspk8nLrAKDpWApV4fnOfvkxHHnfCXAeLKQFk8iRgls0KmUkPVSSv 51BUKonpvdL5s2iaaeLXx7Zb3b5eRM9NRZYXm6DHxnf92OXF5GF1ZBXBwGjsphYi toxBWvMsx+IzxTsT/lIjqK1IUUcdmOZ0R295X7S6Xa+dzGru1GoiSFpJTE9Vvw3r pUqj7H+niL60sgkVZAxeQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:date:feedback-id :feedback-id:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:sender:subject:subject:to:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; t=1662909729; x=1662996129; bh=7+iC5s8FgSKUF9eNq0b5LM0BDZdX yuoyNj2kOm272bE=; b=bSsXGNwpe+yvwiittagQcXRrhjNFdUVvVGHdt/0udQ78 fvJ5muWNaPU0EpPrYCuozD9OOexsd2GeXJ4EpIio8t1D4yV43uPCHZd/qrV2exVJ b0jcLOL7aSuCeDNz47YG/5ytH5ona9Oo3aqJ/ijcDqjLzCBAe3hZ20k4AqiYxjAJ yS/6AYPo6MmpBoM2Eaz0R5NqDoeiTrfY33fz585gd5G6Ojb0MZbcZuJX/AEjRvnp t0uzDuJHkhwx10lpHiErhGOKq4umHEczyjtH6FLvuJ8Ti8/NcHjDVN4OolxKz8uK wbnV5GV5u++NQPJX9tuxIRyThgSfSrcSyT6RW6On5A== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrfedutddgledtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgesthdtredtreertdenucfhrhhomhepfdfnrghr rhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtoh hmqeenucggtffrrghtthgvrhhnpeeglefgkeduiedvvdetffeujefftdfhjeeiveehgfff keduveektddvledvvdfffeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmh grihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 897D41700083; Sun, 11 Sep 2022 11:22:09 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.7.0-alpha0-927-gf4c98c8499-fm-20220826.002-gf4c98c84 Mime-Version: 1.0 Message-ID: In-Reply-To: References: Date: Sun, 11 Sep 2022 10:21:49 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] Re: Issues with readonly classes From: larry@garfieldtech.com ("Larry Garfield") On Sat, Sep 10, 2022, at 4:34 PM, Nicolas Grekas wrote: > Hello Larry, > > >> Regarding your main question: I understand your problem with readonly >> > classes, and I'd be happy if we found a solution which fits your >> use-cases >> > and keeps consistency for the engine at the same time. To give you more >> > context about the inheritance related restriction in the RFC: I went with >> > forbidding the extension of readonly classes by non-readonly ones so that >> > the invariants of the parent (no dynamic or mutable properties are >> allowed) >> > don't occasionally get violated by the child. However, I cannot think >> about >> > a proper scenario now where this would cause any problems... I'm >> wondering >> > if anyone could come up with one? >> >> I don't have a real-world example, but a general pattern. The advantage >> of a readonly object (either conventionally like PSR-7 or enforced by the >> `readonly` keyword) is that you can store a reference to it without having >> to worry about it changing out from under you. That means you can code on >> the assumption that any data derived from that object is also not subject >> to change. >> >> If you accept a readonly object of type Foo, you would write code around >> it on that assumption. >> >> If you're then passed an object of type Bar extends Foo, which has an >> extra non-readonly property, that assumption would now be broken. Whether >> that counts as a Liskov violation is... a bit squishy, I think. >> >> Where that might be a problem is a case like this: >> >> readonly class Person { >> public function __construct(public string $first, public string $last) {} >> >> public function fullName() { >> return "$this->first $this->last"; >> } >> } >> >> class FancyPerson extends Person { >> public string $middle = ''; >> >> public function setMiddle(string $mid) { >> $this->middle = $mid; >> } >> >> public function fullName() { >> return "$this->first $this-middle $this->last"; >> } >> } >> >> class Display { >> public function __construct(protected Person $person) {} >> >> public function hello() { >> return "Hello " . $this->person->fullName(); >> } >> } >> >> Now, Display assumes Person is readonly, and thus fullName() is >> idempotent, and thus Display::hello() is idempotent. But if you pass a >> FancyPerson to Display, then fullName() is not safely idempotent (it may >> change out from under you) and thus hello() is no longer idempotent. >> >> Whether or not that problem actually exists in practice is another >> question. And to be fair, the same risk exists for conventionally-readonly >> classes today (PSR-7, PSR-13, etc.), unless they're made final. Arguably >> the safety signaling of a lexically readonly class is stronger than for a >> conventionally readonly class, so one would expect that to not be broken. >> But that's the case where a non-readonly child of a readonly parent can >> cause problems. >> > > Thanks for constructing this example, that's good food for thoughts. > Unfortunately, The code following readonly child class shows that this > safety you describe doesn't exist: > > readonly class FancyPerson extends Person { > private readonly stdClass $middle; > > public function setMiddle(string $mid) { > $this->middle ??= new stdClass; > $this->middle->name = $mid; > } > > public function fullName() { > return "$this->first $this-middle $this->last"; > } > } Hm. I seem to recall during the discussion of readonly classes someone saying that object properties of a readonly class had to also be readonly classes, which would render the above code a compile error. However, I just checked and that is not in the RFC. Was it removed? Am I imagining things? Anyone else know what I'm talking about? :-) --Larry Garfield