Re: [RFC] Readonly property hooks
| From: | Nick | Date: | Fri, 11 Jul 2025 10:02:37 +0000 |
| Subject: | Re: [RFC] Readonly property hooks | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-128008@lists.php.net to get a copy of this message | ||
> On 11. Jul 2025, at 13:02, Rob Landers <rob@bottled.codes> wrote:
>>
>> Please remember that the RFC will allow
readonly on backed
>> properties only, not on virtual hooked properties.
>> Nothing from your example would work, and it would result in:
>> Fatal error: Hooked virtual properties cannot be declared readonly
>> My proposed alternative implementation with caching addresses the concern Claude and Tim
>> had and will make this hold:
>>
>> ```php
>> class Unusual
>> {
>> public function __construct(
>> public readonly int $value {
>> get => $this->value * random_int(1, 100);
>> }
>> ) {}
>> }
>>
>> $unusual = new Unusual(1);
>> var_dump($unusual->value === $unusual->value); // true
>> ```
>>
>> – Nick
>
> Hey Nick,
>
> I was merely illustrating the different types, you can simply replace them with non-virtual
> examples. To your idea of forced memoization, I'm not sure that's a good idea. In cases
> where its a single execution context per request, it may be fine, but in cases of worker mode on
> frankenphp, where readonly objects may live for quite awhile, it may not be. Generally, memoization
> is an optimization, not a property of a value.
>
> In your example above, this breaks the principle of least astonishment, and potentially
> violates referential transparency due to the calculation being non-pure. Referential transparency
> basically says we can can replace the use of the variable with it's value (in this case,
> $ususual->value with $unusual->backing_value * random_int(1, 100)). If it is memoized, we
> cannot. There isn't a way to express that it is one value the first time (random) and a
> different value the next time (the previous computation). This is a bit dangerous because the
> programmer has no way to reliably reason about the code as if the expression can be substituted
> freely.
>
> — Rob
Hey Rob,
1) Well, we cannot have it both in the same time. Either we want a strict guarantee that the value
doesn’t change after the first get hook call on a readonly property, or
we want the opposite. So the proposed solution now is to be strict by default. If you want it
non-cached you can use non readonly.
2) The same point could be made outside of "readonly hooks", for everything with any kind
of randomness or external state (database, filesystem, …) source. That’s the trade-off.
I find it very acceptable as a solution for the concern brought up by Claude and Tim.
Cheers,
Nick
Aside: I just learned about your “records” RFC. Good stuff!