On 2 September 2016 at 15:59, Silvio Marijić <marijic.sil...@gmail.com>
wrote:

> Michal I'm talking about __clone() callback after clone operation. But I
> agree with you about syntax part.
>
> 2016-09-02 16:46 GMT+02:00 Michał Brzuchalski <
> michal.brzuchal...@gmail.com>
> :
>
> > 02.09.2016 16:29 "Larry Garfield" <la...@garfieldtech.com> napisał(a):
> > >
> > > On 09/02/2016 09:06 AM, Silvio Marijić wrote:
> > >>
> > >> Well at the moment expection is thrown in case when you try to clone
> > >> immutable object. But you do seem to have valid point there regarding
> > >> __clone method. I'm definitely going to give it a thought.
> > >>
> > >> Best,
> > >> Silvio.
> > >>
> > >> 2016-09-02 15:52 GMT+02:00 André Rømcke <andre.rom...@ez.no>:
> > >>
> > >>>
> > >>>> On Sep 2, 2016, at 09:10 , Silvio Marijić <marijic.sil...@gmail.com
> >
> > >>>
> > >>> wrote:
> > >>>>
> > >>>> Hi Fleshgrinder,
> > >>>>
> > >>>> Since Michal answered most of the questions, I'll just add some
> notes.
> > >>>> Initially I added restrictions to abstract classes, but I did think
> > about
> > >>>> that over the last couple of days and couldn't find any concrete
> > reason
> > >>>
> > >>> for
> > >>>>
> > >>>> that restriction, so I think I'm going to remove that. As far as
> > cloning,
> > >>>> it is disabled for immutable objects, because you'll end up with the
> > copy
> > >>>> of object that you can not modify. I did mention in Cons sections
> that
> > >>>> cloning is disabled, maybe it should be made more clear.
> > >>>
> > >>>
> > >>> _If_ there are use-cases for it, wouldn’t it also be safe that the
> > clone
> > >>> is allowed to be modified during __clone() and afterwards sealed?
> Like
> > in
> > >>> __construct().
> > >>> And if you don’t want to allow cloning, throw in __clone.
> > >>>
> > >>> Best,
> > >>> André
> > >
> > >
> > > I'd have to agree here.  I love the idea of "lockable" immutable
> > objects.  However, the __clone() method has to be a modifiable area just
> > like __construct() or else it's effectively useless for anything more
> than
> > a trivial object.
> > >
> > > This was one of the main concerns with immutability in the PSR-7
> > discussions.  Consider this sample class, with 8 properties (entirely
> > reasonable for a complex value object):
> > >
> > > immutable class Record {
> > >   public $a;
> > >   public $b;
> > >   public $c;
> > >   public $d;
> > >   public $e;
> > >   public $f;
> > >   public $g;
> > >   public $h;
> > >
> > >   public function __construct($a, $b, $c, $d, $e, $f, $g, $h) {
> > >     $this->a = $a;
> > >     $this->b = $b;
> > >     $this->c = $c;
> > >     $this->d = $d;
> > >     $this->e = $e;
> > >     $this->f = $f;
> > >     $this->g = $g;
> > >     $this->h = $h;
> > >   }
> > > }
> > >
> > > Now I want a new value object that is the same, except that $d is
> > incremented by 2.  That is, I'm building up the value object over time
> > rather than knowing everything at construct time.  (This is exactly the
> use
> > case of PSR-7.)  I have to do this:
> > >
> > > $r1 = new Record(1, 2, 3, 4, 5, 6, 7, 8);
> > >
> > > $r2 - new Record($r1->a, $r1->b, $r1->c, $r1->d + 2, $1->e, $r1->f,
> > $r1->g, $r1->h);
> > >
> > > That's crazy clunky, and makes immutable objects not very useful.
> Imagine
> > a money object where you had to dissect it to its primitives, tweak one,
> > and then repackage it just to add a dollar figure to it.  That's not
> worth
> > the benefit of being immutable.
> > >
> > > The way PSR-7 addressed that (using fake-immutability, basically), was
> > this:
> > >
> > > class Response {
> > >   // ...
> > >
> > >   protected $statusCode;
> > >
> > >   public function withStatusCode($code) {
> > >     $new = clone($this);
> > >     $new->statusCode = $code;
> > >     return $new;
> > >   }
> > > }
> > >
> >
> > I see only way in somehow invoking closere with cloning. That'll need
> > additional syntax. Clone is left side operator not a function - it's not
> > being called with parenthesis. If this was an object method accessible
> from
> > public it coud gace such closure injected...
> >
> > > That is, outside of the object there's no way to modify it in place,
> but
> > it becomes super easy to get a slightly-modified version of the object:
> > >
> > > $r2 = $r1->withStatusCode(418);
> > >
> > > And because of PHP's copy-on-write support, it's actually surprisingly
> > cheap.
> > >
> > > For language-level immutable objects, we would need some equivalent of
> > that behavior.  I'm not sure exactly what form it should take (explicit
> > lock/unlock commands is all I can think of off hand, which I dislike),
> but
> > that's the use case that would need to be addressed.
> > >
> > > --Larry Garfield
> > >
> > >
> > > --
> > > PHP Internals - PHP Runtime Development Mailing List
> > > To unsubscribe, visit: http://www.php.net/unsub.php
> > >
> >
>
>
>
> --
> Silvio Marijić
> Software Engineer
> 2e Systems
>

The issue with handling updates on clone to immutable objects was the
reason I left the proposal to fade away last time.

Your RFC is fairly close to what I originally had in mind with some small
tweaks. To sum up what my proposal was:

- Properties can be declared immutable. Immutable properties may only be
changed under two circumstances: a) In the objects constructor b) If they
are null (This enables setter injection if required)
- Classes can be declared immutable. This is a short hand for making every
property immutable but also prevents any dynamic properties (eg not
declared at compile time) from being set outside of the constructor.
- Arrays assigned to immutable properties would not be possible to change
- Objects assigned to immutable properties would be possible to change, so
long as the same object remained assigned to the property.

The two key differences between my ideas and your current RFC are 1) No
limitation against assigning mutable objects to immutable properties 2)
Allow setting of properties which are currently unset (eg null) at any
point.

>From a developer adoption point of view, I think these two points are
important to making immutable classes generally useful. Without 1, it will
be a nuisance to use 3rd party libraries esp those which retain
compatibility for PHP < 7.2. Without 2 you block the ability to use setter
injection, which I personally would be in favour of if it meant that devs
stopped using it - it wouldn't - they would simply not use immutable
classes, loosing the benefits thereof.

Dealing with the clone issue some of my ideas since then were:

- Seal/Unseal (As per Larry's suggestion)
- Parameters to __clone; in this instance the clone method would be allowed
to change properties of the object as well as the constructor. This feels
like it may breach the principal of least surprise as cloning an object no
longer guarantees an exact copy.
- A new magic method __mutate($property, $newvalue) called instead of a
fatal error when a property is changed. This probably lays too many traps
for developers for it to be a good idea.
- Implicitly returning a new object whenever a property is changed. Similar
reservations to the above.
- A new magic method __with($newInstance, $args) and a keyword with that is
used in place of clone eg $x = $y with ($arg1, $arg2); in this instance,
__with receives a clone of $y (after calling __clone) and an array [$arg1,
$arg2] the with magic method is allowed to mutate $newInstance and must
return it. This is currently my favoured solution

~C

Reply via email to