Re: Analysis of property visibility, immutability, and cloning proposals
| From: | Mike Schinkel | Date: | Thu, 31 Dec 2020 00:24:53 +0000 |
| Subject: | Re: Analysis of property visibility, immutability, and cloning proposals | ||
| References: | 1 2 3 4 5 6 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-112691@lists.php.net to get a copy of this message | ||
> On Dec 30, 2020, at 1:15 PM, Rowan Tommins <rowan.collins@gmail.com> 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.
"User-friendliness" of this nature is in the eye of the beholder.
A different perspective is that "withX" methods require a mental translation where
"addX" methods do not, much like how a person whose native language is English will find
it a challenge to (or cannot) "think" in French.
> 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);
Ignoring that you are comparing apples and oranges (scalars to objects,) the latter is easier to
reason about IMO.
> 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.
-Mike