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]

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

Reply via email to