On Wed, Dec 30, 2020, at 12:15 PM, Rowan Tommins wrote:
> On 30/12/2020 13:49, Olle Härstedt wrote:
> > Uniqueness is when you only allow _one_ reference to an object (or
> > bucket of memory).
> > [...]
> >
> > You can compare a builder pattern with immutability vs non-aliasing
> > (uniqueness):
> >
> > ```
> > // Immutable
> > $b = new Builder();
> > $b = $b->withFoo()->withBar()->withBaz();
> > myfun($b);  // $b is immutable, so $b cannot be modified by myfun()
> > return $b;
> > ```
> >
> > ```
> > // Uniqueness
> > $b = new Builder();  // class Builder is annotated as non-aliasing/unique
> > $b->addFoo();
> > $b->addBar();
> > $b->addBaz();
> > myfun(clone $b);  // HAVE TO CLONE TO NOT THROW EXCEPTION.
> > return $b;
> > ```
> 
> 
> Thanks, I can see how that solves a lot of the same problems, in a very 
> robustly analysable way.
> 
> However, from a high-level user-friendliness point of view, I think 
> "withX" methods are actually more natural than explicitly cloning 
> mutable objects.
> 
> Consider the case of defining a range: firstly, with plain integers and 
> familiar operators:
> 
> $start = 1;
> $end = $start + 5;
> 
> This models integers as immutable values, and + as an operator which 
> returns a new instance. If integers were mutable but not aliasable, we 
> would instead write something like this:
> 
> $start = 1;
> $end = clone $start;
> $end += 5; // where += would be an in-place modification, not a 
> short-hand for assignment
> 
> I think the first more naturally expresses the desired algorithm. It's 
> therefore natural to want the same for a range of dates:
> 
> $start = MyDate::today();
> $end = $start->withAddedDays(5);
> 
> vs
> 
> $start = MyDate::today();
> $end = clone $start;
> $end->addDays(5);
> 
> 
> To put it a different way, value types naturally form *expressions*, 
> which mutable objects model clumsily. It would be very tedious if we had 
> to avoid accidentally mutating the speed of light:
> 
> $e = (clone $m) * ((clone $c) ** 2);
> 
> 
> > The guarantee in both above snippets is that myfun() DOES NOT modify
> > $b before returning it. BUT with immutability, you have to copy $b
> > three times, with uniqueness only one.

That's a good summary of why immutability and with-er methods (or some 
equivalent) are more ergonomic.

Another point to remember: Because of PHP's copy-on-write behavior, full on 
immutability doesn't actually waste that much memory.  It does use up some, but 
far less than you think.  (Again, based on the tests MWOP ran for PSR-7 a ways 
back.)

> I wonder if that difference can be optimised out by the 
> compiler/OpCache: detect clones that immediately replace their original, 
> and optimise it to an in-place modification. In other words, compile 
> $foo = clone $foo with { x: 42 } to $foo->x = 42, even if the clone is 
> actually in a "withX" method.

In concept, maybe?  That's well above my pay grade. :-)

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to