Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:109127 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 22043 invoked from network); 18 Mar 2020 16:35:29 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 18 Mar 2020 16:35:29 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 368871804D3 for ; Wed, 18 Mar 2020 07:58:25 -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.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS11403 66.111.4.0/24 X-Spam-Virus: No X-Envelope-From: Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) (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, 18 Mar 2020 07:58:24 -0700 (PDT) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 28DB95C01B4 for ; Wed, 18 Mar 2020 10:58:24 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Wed, 18 Mar 2020 10:58:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding: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=fm2; bh=X203qcY7HS/CAdZPAqTyPwuPEJvP8db3BpmNJnC20 kQ=; b=z9wtMK18b8FxqNSebLg2KeN84gBb9W0tlob9msFZwdKyS4+0VQJ3JGYaS b4T9TlX7OZMVMYMHdPdjqIL+t2m5BaN+9PokzNf+iL6nBhLTia96S+rbdSlEmEIQ VzE8JK0u/s6daPGis4x8oLV7GOeeI/Lutgvbrixz1NyiKbKmG3qOgJ437XfTatiZ 5N+HJk7huHXAhegS2HL8RA9PNCV3nkOLgIC23KtJZLtQpLg2yq+eB8S6HJObARJj F4lDRXLQky8wYsqFFr3YpKsF69HBJok8/xwNhll5h5/zUiCmScZRKyRraa2d2dCO tO5s7ZS4nA6/f+mc+4aFu0mExSFsA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudefjedgjedtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgfgsehtqhertderreejnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhep lhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id A2FAC14200A2; Wed, 18 Mar 2020 10:58:23 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.1.7-991-g5a577d3-fmstable-20200305v3 Mime-Version: 1.0 Message-ID: In-Reply-To: References: Date: Wed, 18 Mar 2020 09:58:03 -0500 To: "php internals" Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] [RFC] [VOTE] Immutable/final/readonly properties From: larry@garfieldtech.com ("Larry Garfield") On Tue, Mar 17, 2020, at 1:07 PM, M=C3=A1t=C3=A9 Kocsis wrote: > At this point I'd like to repeat one of my previously mentioned argume= nts > for the feature: > if we have an immutable PSR-7 that is used all over the PHP ecosystem,= and > we also have > lots of people who wish for more type-level strictness by using immuta= ble > DTOs or VOs, > why don't we provide a proper way to achieve immutability? If there is= such > a need > then I think we should react. Even more so, because the same feature i= s > available in other > languages where we usually copy from, so it wouldn't even be without > precedents. > (Just to be clear: I don't think that we have to copy everything from = Java > or C#. :) ) I don't have voting rights yet, but I would also vote no as is precisely= because of the PSR-7 type case, along the same lines that Nicolas is ar= guing. Currently, a PSR-7 implementation does something like this (assuming it = were updated to typed properties): class Response implements ResponseInterface { private int $statusCode; public function getStatusCode : string { return $this->statusCode; } public function withStatusCode(int $code): self { $new =3D clone($this): $new->statusCode =3D $code; return $new; } } Now repeat that for about 10 different properties across 3 different obj= ects, and sometimes with multiple variations on the with*() method. Allowing the status code to be declared public-readonly would change it = to this: class Response implements ResponseInterface { public readonly int $statusCode; public function withStatusCode(int $code): self { $new =3D new static( $code,=20 $this->headers,=20 $this->protocolVersion,=20 $this->body ); return $new; } } And that's for Response, which is the simplest of the message objects in= PSR-7. That is, you get to skip the trivially easy method (a positive) in retur= n for having a longer and more involved with*() method, which you alread= y have more of to begin with (a negative), and for forcing you to have a= constructor that takes every possible property (a negative). =20 That is not a net win. Thinking about it, Uri is possibly an even better example as it has 8 pr= operties: class Uri implements UriInterface { private string $scheme; private string $authority; private string $userInfo; private string $host; private int $port private string $path; private array $query; private string $fragment; // These methods could all go away, but they're the simple ones: public function getScheme() { return $this->scheme; } public function getAuthority(); public function getUserInfo(); public function getHost(); public function getPort(); public function getPath(); public function getQuery(); public function getFragment(); // Whereas these turn from this: public function withScheme(string $scheme) { $new =3D clone($this); $new->scheme =3D $scheme; return $new; } // In this: public function withScheme(string $scheme) { $new =3D static( $scheme,=20 $this->authority,=20 $this->userInfo,=20 $this->host,=20 $this->port,=20 $this->path,=20 $this->query,=20 $this->fragment ); return $new; } // And doing so for all of these methods, but slightly differently: public function withUserInfo($user, $password =3D null); public function withHost($host); public function withPort($port); public function withPath($path); public function withQuery($query); public function withFragment($fragment); } So switching it to use readonly properties as proposed here, would invol= ve: * More complex methods * A mandatory 8 parameter constructor * Avoiding the trivial methods in exchange for the mandatory methods bei= ng longer. Honestly... that's not usable for value objects. I love value objects, = I love immutable values, and I would find this property useless in its c= urrent form. Also, I just realized... properties cannot be defined in interfaces. Th= at means a PSR interface (or any other interface) could not require that= they be defined, which means they cannot be made part of a contract. T= hat renders readonly properties as defined here unusable by FIG entirely= . Requiring that properties be typed to be readonly is fine with me. But = the way it renders cloning unusable for evolvable objects makes evolvabl= e objects considerably harder to use and to standardize, not easier. And this property co-existing with some other way of achieving the same = goal (whether that's something like Nicolas's proposal or something enti= rely different) would only lead to confusion and people doing one, reali= zing they should have done the other, and having more BC breaks now in t= heir own code. I appreciate the work that Mate has put into this proposal, but as is I = have to encourage people to vote no. --Larry Garfield