Re: Immutable modifier
| From: | Rowan Collins | Date: | Mon, 16 Nov 2015 11:30:31 +0000 |
| Subject: | Re: Immutable modifier | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-89232@lists.php.net to get a copy of this message | ||
Mathieu Rochette wrote on 16/11/2015 10:00:
Would it be allowed to assign non immutable types to properties of an immutable class ?I think this is the trickiest part of trying to enforce immutability: nesting. Consider the following: // Basic properties $my_immutable_object->foo = 42; $my_immutable_object->foo++; // Nested object - implicitly immutable? required to be explicitly immutable? $my_immutable_object->bar->something = 42; $my_immutable_object->bar->setSomething(42); // Array access - no idea how this should work $my_immutable_object->quux[0] = 42; $my_immutable_object->quux[] = 'Hello'; $my_immutable_object->quux['World'][0]['X'] = 'A'; The other problem is that to be useful, certain functions usually need to be able to mutate the state of objects which are officially immutable. For instance, implementations of PSR-7 need a set of copy constructors for the withX methods. You could do this using the suggested rule that immutability applies only to non-null properties, and manually populate every property of an empty instance, but it's much more efficient to "clone $this" and then change the one property that needs to be different. For this particular example, you could write quite a nice implementation by "freezing" the instance once it's initialised: // example plucked from https://github.com/guzzle/psr7/blob/master/src/Request.php#L101
public function withMethod($method)
{
// The method starts by making a mutable clone of the immutable $this
$new = clone $this;
$new->method = strtoupper($method);
# SUGGESTED ADDITION: new keyword to set an object to be immutable
freeze $new;
// After this point, nothing should be able to mutate the new object, only clone it
return $new;
}
The freeze operation could perhaps be recursive, or perhaps it could work like "clone", with an "__freeze" method responsible for freezing nested objects as necessary. The ability to freeze an array would also be useful in that case...
I realise this is a lot more complex than the original suggestion, but I think something of this level of detail is needed to make it useful.
Regards,
--
Rowan Collins
[IMSoP]