Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119037 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 32930 invoked from network); 26 Nov 2022 22:56:43 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 26 Nov 2022 22:56:43 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id EC473180211 for ; Sat, 26 Nov 2022 14:56:41 -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=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-pl1-f179.google.com (mail-pl1-f179.google.com [209.85.214.179]) (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 ; Sat, 26 Nov 2022 14:56:41 -0800 (PST) Received: by mail-pl1-f179.google.com with SMTP id d3so1960686plr.10 for ; Sat, 26 Nov 2022 14:56:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=jjKReQwgnVfTDgUrfrUlfBTv3FJZaMmYnuKBQYiAUyM=; b=J8tCbDX0+iUtj1Lngoq0Zz/EpR1CNxPERtJ3ct57EGUXdRvYo8Lh9p9Djp/pkvXSWQ QxKVOaByrgSWnMSkGDvte0GKYIAKXzZiQGYe2wHb59fwhyjmhqZw5zJxX/KCqMqEdxks yXuhLns+1RGsuDaLOpJJjN5EehPGxa/lhIOL/x8kAgeTXhvJpwD72Al6MEMnjxuO0qEi iLBtV49E2R63lQVDoqz0lOWwx/2npVcDujQjvlVrya0P17XE8izJd+c+JTeAoTLLCj7H 6SHpmWjJ5hDzwiv19G0NYFzG0tw0grK6leEp2uoa6sFCp3B42597dgvJhx2/0gQqXoxB Ldtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=jjKReQwgnVfTDgUrfrUlfBTv3FJZaMmYnuKBQYiAUyM=; b=D4gTE8giuYJj9M7y8twkpkMfG2A3k+b2Els4hqfwvMN2rxyfFFeqi294dWDUoCxCXi pVThi5ZemGoRSl79nn7N0OMaDAEuBdASm+Dd+mvOrT2B1Dg+ijuxTYIpNQijbinV4Yhp PWrudfC4sH3dbMDgssi6Zd3H80O7mkrn7byi7oodr2SX77plLv0VsKAO3xLlo3BvLV7w /T3gFQzb5UCstMHaJpQv0FgfeAwuTfePEWp1104qELE0oLT1Zhe+K0k9ArbiiMYHlTLH ju2Fpaf1XkHMi1oblQtGYQotTzkn90kk7uKrseGi1L8SrpNBH6rCNZMwL7/KVjPoZ9Wm UN6Q== X-Gm-Message-State: ANoB5plmU14xI1fqBDZema21JpmrcCLp6jA5SYVVDIQCDNGngL++BT23 VdA/VOrLBQDACGPukQJtIMBmQIvFSadQ8qgTSu7+8CV7EXg= X-Google-Smtp-Source: AA0mqf7i4hliim2n64AH0cgBEtksXQVvWMKdfep3mXh9z+sjISKhhlEKFrUUva9ZpcEIN5yo/KORe3L2lG8BVxUpQ5Q= X-Received: by 2002:a17:90a:4a8f:b0:215:f80c:18e6 with SMTP id f15-20020a17090a4a8f00b00215f80c18e6mr53895715pjh.45.1669503400156; Sat, 26 Nov 2022 14:56:40 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: Date: Sat, 26 Nov 2022 22:56:28 +0000 Message-ID: To: Marco Pivetta Cc: =?UTF-8?B?TcOhdMOpIEtvY3Npcw==?= , PHP Internals List Content-Type: multipart/alternative; boundary="0000000000001e25cc05ee678dc0" Subject: Re: [PHP-DEV] [RFC] [Discussion] Readonly class amendments From: george.banyard@gmail.com ("G. P. B.") --0000000000001e25cc05ee678dc0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, 17 Nov 2022 at 14:47, Marco Pivetta wrote: > Hey M=C3=A1t=C3=A9, > > On Tue, 15 Nov 2022 at 07:30, M=C3=A1t=C3=A9 Kocsis wrote: > > > Hi Everyone, > > > > Following Nicolas' thread about "Issues with readonly classes" ( > > https://externals.io/message/118554), we created an RFC to fix two > issues > > with the readonly behavior: https://wiki.php.net/rfc/readonly_amendment= s > > > > > Since I was reviewing https://github.com/lcobucci/jwt/pull/979 today, I > had > to put the "why immutability is an LSP requirement" in examples. > > As explained in > https://github.com/lcobucci/jwt/pull/979#discussion_r1025280053, a > consumer > relying on a `readonly` implementation of a class probably also expects > replacement implementations as read-only. > I am aware that we lack the `readonly` marker at interface level (would b= e > really neat), but the practical example is as follows: > > > ```php > > /* readonly */ class ImmutableCounter { > public function __construct(private readonly int $count) {} > public function add1(): self { return new self($this->count + 1); } > public function value(): int { return $this->count; } > } > > // assuming the proposed RFC is in place, this is now possible: > class MutableCounter extends ImmutableCounter { > public function __construct(private int $count) {} > public function add1(): self { return new self(++$this->count); } > public function value(): int { return $this->count; } > } > > $counter1 =3D new ImmutableCounter(0); > $counter2 =3D $counter1->add1(); > $counter3 =3D $counter2->add1(); > > var_dump([$counter1->value(), $counter2->value(), $counter3->value()]); > > $mutableCounter1 =3D new MutableCounter(0); > $mutableCounter2 =3D $mutableCounter1->add1(); > $mutableCounter3 =3D $mutableCounter2->add1(); > > var_dump([$mutableCounter1->value(), $mutableCounter2->value(), > $mutableCounter3->value()]); > ``` > > This prints ( https://3v4l.org/IDhRY ) > > ``` > array(4) { > [0]=3D> > int(0) > [1]=3D> > int(1) > [2]=3D> > int(2) > } > array(4) { > [0]=3D> > int(1) > [1]=3D> > int(2) > [2]=3D> > int(2) > } > ``` > > I took a simplified example on purpose, just to demonstrate the problem > with `readonly` disappearing in child classes. > > That's really really confusing, buggy, and, from a consumer PoV, broken > (LSP violation too, transitively). > Removing the readonly restriction for a child class is *not* an LSP violation. As all the invariants will be maintained in the child classes (i.e. all the properties of the parent class remain readonly). Moreover, a consumer of the base class can only rely on the API defined by said class, as such it will not be aware of any mutable properties defined by a child class. LSP is really not about the class hierarchy/subtypes itself, but the relation of input data and output data of the operations allowed on a type (i.e. method calls or property access), and because readonly is not the same as immutability there is no theoretical issue. Now, I can agree that it can be slightly surprising that a class which has a writeable property extends from one which only has readonly ones, but one can already immitate this by declaring every property readonly but not the class. Best regards, George P. Banyard --0000000000001e25cc05ee678dc0--