Re: Analysis of property visibility, immutability, and cloning proposals

From: Date: Wed, 30 Dec 2020 18:15:31 +0000
Subject: Re: Analysis of property visibility, immutability, and cloning proposals
References: 1 2 3 4 5  Groups: php.internals 
Request: Send a blank email to internals+get-112671@lists.php.net to get a copy of this message
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.
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. Regards, -- Rowan Tommins [IMSoP]

« previous php.internals (#112671) next »