Re: [RFC] Readonly property hooks
| From: | Eric Norris | Date: | Sun, 13 Jul 2025 18:15:21 +0000 |
| Subject: | Re: [RFC] Readonly property hooks | ||
| References: | 1 2 3 4 5 6 7 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-128022@lists.php.net to get a copy of this message | ||
On Sun, Jul 13, 2025 at 2:00 PM Marc Bennewitz <marc@mabe.berlin> wrote:
>
>
> On 13.07.25 18:17, Nick wrote:
>
>
> On 13. Jul 2025, at 20:38, Marc Bennewitz <marc@mabe.berlin> wrote:
>
> Hi Nick, Claude,
>
> Hey Marc,
>
> I think it's important to explicitly mark it as "this value will be stored in
> memory", I mean just silently caching the get hook could quickly lead to unexpected behavior.
> Like one would expect the value to be changed
>
> The most here made the argument that "a changing value from a readonly get hook"
> would be the unexpected behaviour.
> That’s why we ended up with the current “alternative implementation 2”. Please see my
> last answer to Rob for a fair example [1] .
>
> The current preferred alternative implementation covers both situations....
>
> If a property is
readonly:
> - you can set once
> - on read you always get the same (once computed) value back
>
> This is exactly the behavior I mean which is somehow unexpected if not marked explicitly as the
> result could be cached and the property value will never change.
>
> Not being able to write to something doesn't generally mean reading the value will never
> change. get => random_int(0, 100);
>
> I don't want to say that the path we want to go with readonly being able to assume the
> value will never change is wrong but I think it's not clear for the user and can be missed
> quickly - even with a test as you have to read the property multiple time to notice the difference.
>
>
> If a property is NOT readonly:
> - you can set often
> - on read you always get the fresh (often computed) value back
>
> I argue that this is a very easy mental model.
> I hope that voters agree on “cached may be implied by readonly”, as Claude called it.
>
> All what I'm saying is that this behavior should be explicit and not applied implicitly on
> a readonly get hook.
I agree with Marc here, not surprisingly.
> To have an init hook doesn’t solve the get hook issue.
>
> As far as I understood the init hook it would still disallow readonly+get but allow
> readonly+init and init would be called once the first time the property gets read and the result
> would end up in the backing store.
>
> As a result you get the same behavior as cached get with the
> only difference that you write init => random_int(); instead of
> cached get => random_int();
Agreed. Nick, I am not sure how the init hook doesn't "solve the get
hook issue". As I understand it, the get hook issue is that get hooks
are not allowed on readonly properties. The init hook would be
identical to a "cached get" hook on a readonly property, so why
doesn't it solve the issue?
> Or did I misunderstand it?
I share the same understanding as you, Marc.
> The cached modifier I would expect to be an attribute applicable to any function which uses
> another cache store similar to how it's possible in python to memorize function calls which
> would be a very different feature.
>
> As earlier answered to Claude [2], I seek to write less code. To introduce a
> cached modifier voids this for no strong reason (please see
> “mental model” above).
>
> See above - and init is just once more character.
I was going to respond to this point earlier, but Marc beat me to it.
An "init" hook is one more character than a get hook, is explicit over
a get hook that works differently only for readonly properties, *and*
is far fewer characters than the explicit "cached" modifier get hook
option.
On top of that, as Claude mentioned an init hook provides the ability
to differentiate between a null property and an uninitialized property
- an init hook would only be called for uninitialized properties, so
no need for $this->foo ??= "bar".