Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95598 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 43117 invoked from network); 3 Sep 2016 14:56:05 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 3 Sep 2016 14:56:05 -0000 Authentication-Results: pb1.pair.com smtp.mail=php@fleshgrinder.com; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=php@fleshgrinder.com; sender-id=unknown Received-SPF: error (pb1.pair.com: domain fleshgrinder.com from 77.244.243.86 cause and error) X-PHP-List-Original-Sender: php@fleshgrinder.com X-Host-Fingerprint: 77.244.243.86 mx105.easyname.com Received: from [77.244.243.86] ([77.244.243.86:60501] helo=mx207.easyname.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id EF/F0-32927-284EAC75 for ; Sat, 03 Sep 2016 10:56:04 -0400 Received: from cable-81-173-132-156.netcologne.de ([81.173.132.156] helo=[192.168.178.20]) by mx.easyname.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1bgCMQ-0001Br-Gm for internals@lists.php.net; Sat, 03 Sep 2016 14:55:58 +0000 Reply-To: internals@lists.php.net References: <167d6432-e4d6-d87d-5d31-d3d82a8de4ce@fleshgrinder.com> <99F80C06-654D-4109-BE07-2FA5B1073E5D@ez.no> <4f54308a-4a69-2e6b-2ed0-51d4336d1cd4@fleshgrinder.com> <5969d1af-48e5-1376-07fe-9568de538145@texthtml.net> To: internals@lists.php.net Message-ID: <224f0c67-d511-4ad1-08d8-57cdc76522f0@fleshgrinder.com> Date: Sat, 3 Sep 2016 16:55:46 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="b9nnJNAo1fbEwJsxFiDVA1Aqek70WPVPQ" Subject: Re: [PHP-DEV] RFC - Immutable classes From: php@fleshgrinder.com (Fleshgrinder) --b9nnJNAo1fbEwJsxFiDVA1Aqek70WPVPQ Content-Type: multipart/mixed; boundary="lqCife9kEgbpDR3T83ApMOlvuiUstXHVf"; protected-headers="v1" From: Fleshgrinder Reply-To: internals@lists.php.net To: internals@lists.php.net Message-ID: <224f0c67-d511-4ad1-08d8-57cdc76522f0@fleshgrinder.com> Subject: Re: [PHP-DEV] RFC - Immutable classes References: <167d6432-e4d6-d87d-5d31-d3d82a8de4ce@fleshgrinder.com> <99F80C06-654D-4109-BE07-2FA5B1073E5D@ez.no> <4f54308a-4a69-2e6b-2ed0-51d4336d1cd4@fleshgrinder.com> <5969d1af-48e5-1376-07fe-9568de538145@texthtml.net> In-Reply-To: --lqCife9kEgbpDR3T83ApMOlvuiUstXHVf Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hey guys :) # Abstract Classes Establishing a contract that any child class of an abstract class has to be immutable is a totally valid use case in my opinion and it aids consistency. Otherwise we have the same situation as with final which I never understood. Actually, even interfaces could benefit from this modifier. # Clone What Larry illustrated is exactly how I build immutable value objects right now too. However, cloning as we have it is not what we want, we want a mutable clone while cloning is not allowed to the outside world. It simply makes no sense to clone a value object for the same reason as it makes no sense to clone a string. On a side note, I always change the visibility of the __clone callback in my value objects to protected/private and disable cloning for the outside world this way. Cloning a value object is a programming error and not something that should be catchable and recoverable. I see various ways to approach this topic and did not include anything in the previous message because I wanted to think a bit more about it. ## Proposal 1 My first proposal would be to allow mutation within the class itself but directly creating a copy to ensure integrity and immutability of the current instance. final immutable class ValueObject { public $value; public function withValue($value) { $this->value =3D $value; return $this; } } The write is happening in a compatible context (within the class), however, the $this variable contains a copy of the original now with the changed value instead of the actual instance. Not returning it means that it is simply lost and the state of the current instance is never touched. public function withValue($value) { if ($value !=3D=3D null) { $this->value =3D $value; } return $this; } If $value is null the same instance is returned as is since no write happened. The only thing I do not like about this approach is that it is implicit and not explicit. At the same time it avoids all kinds of problems since the engine handles everything for you and it requires less typing. ## Proposal 2 The __clone callback returns an instance that is mutable within the class itself but not from the outside. This is pretty much like the first proposal but making the clone operation explicit. Note that any write to the current instance would always be an error here. public function withValue($value) { if ($value !=3D=3D null) { $copy =3D clone $this; $copy->value =3D $value; return $copy; } return $this; } Significantly more typing and of course a source of error because the engine does not take care of the work for you. # Arrays and Resources This definitely needs clarification in the RFC since it is a very important restriction. # Flyweight Thinking about it, it's actually possible with the current implementation to create it by simply leaving of the modifier from the class. final class Flyweight { private static $instances =3D []; public immutable $value; } Hence, forget about the remark. # Dynamic Properties Should definitely error on write and it should be explained in the RFC. --=20 Richard "Fleshgrinder" Fussenegger --lqCife9kEgbpDR3T83ApMOlvuiUstXHVf-- --b9nnJNAo1fbEwJsxFiDVA1Aqek70WPVPQ Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJXyuR6AAoJEOKkKcqFPVVrKLkP/RUw4Q+VpKveJW5SHh8rPK89 MQWVNykgsyRPNG8CsR1C7qeDowgAJ+t6e9kmmP2Ow4FT5If5CDWd65nN+MS5mlAZ vWdzv09bwJ2A2CgGdw/E4WgfzVG0/kZEHrswfPJ6zh9HJCJ4+v8POpkUX33q1G7+ BV6sWbnvXDHwnbliybp/yTls+KkG+EfC2C7UCxDapScYP0lFtgF6nEG0NvnrNtaA L9movnN6HQXRbaShXvsKHLP8+NL5SMuloMN4+g2D/j3HPCtt4xPEDzl7X4Gamu2q 7v3xfB5vPxFvS7EZatkceM5HbM8r1IpKYHuPuBLk1g4kCvygO3i9nVGCWhiVmpTz Zw54GVZLvzuZLoRQ1rHQmMn/RT4wIKL2NX5ERNfhhbieQ3sPjFHM98voP+JsoYLF GJ7YrzqYRLKTghryiVWdLJoj4fRzXaokQUumWhvTaVXzF6tK0Oj6BAwIYB8HgqVg /nmVUPmVIl+JTQ2andQSRSx8StIvBJDlgZHBc/tCCiGMNH0Jwr0p99EOorYJZ0RG rugsYjw3zMJPfiiJOnKihKjX6lrUx5DfnvZQoE0g7FuUJcD+XbAvrUj/S01pLk2M 663p7ttY+I8KNVDrhSeXcRftQ/RDQbGVuHYtDEI2G4nx0SAf5WaLdRbbTqYM1jhP MPgKBaAjjxganuc/suRL =/Tdw -----END PGP SIGNATURE----- --b9nnJNAo1fbEwJsxFiDVA1Aqek70WPVPQ--