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".