On Fri, 18 Jul 2025, 15:16 Tim Düsterhus, <t...@bastelstu.be> wrote:

> Hi
>
> On 7/9/25 16:05, Larry Garfield wrote:
> > 1. `readonly` bills itself as immutability, but it fundamentally is
> not.  There are at least two loopholes: __get and a mutable object saved to
> a property.  So while it offering immutability guarantees is nice in
> theory, it's simply not true in practice.  `readonly` has always been
> misnamed; it should really be `writeonce`, because that's all it is.  (Once
> again, this is likely the most poorly designed feature we've added in many
> years.)
>
> No, readonly is readonly, not writeonce. Stop trying to redefine
> readonly as writeonce to justify bad design decisions.
>
> Readonly guarantees that once I successfully read from a property that
> I'll get the same thing out on subsequent reads and I consider this to
> be valuable and strongly disagree on the "most poorly designed feature"
> bit.
>
> Yes, I understand that __get() currently is an exception to that
> guarantee, but that does not mean that further exceptions should be
> added to water down readonly into something that is completely useless.
>
> > 2. In 8.4, if a class is marked `readonly`, you basically forbid it from
> having any hooks of any kind, even though you absolutely can honor the
> write-once-ness of the properties while still having hooks.  And that
> applies to child classes, too, because `readonly`-ness inherits.  So adding
> a single hook means you have to move the readonly to all the other
> properties individually, which if inheritance is involved you cannot do.
> >
> > The RFC aims to address point 2 in a way that still respects point 1,
> but only point 1 as it actually is (write-once), not as we wish it to be
> (immutability).
>
> Readonly is immutability of values (or in other words immutability of
> identity). For objects this means immutability of the object handle, for
> other types this means actual immutability.
>
> I also feel compelled to mention at this point that the commonly
> repeated statement of "Objects are passed by reference" is incorrect.
> It's that "the object handle is passed by value". And then it's fully
> consistent with how readonly works as of now.
>
> > * set hooks for validation, which don't impact writeonce-ness.  I think
> everyone seems on board with that.
>
> Yes, allowing set hooks for readonly properties seems sound to me.
>
> > * Lazy computed properties.  I use these a ton, even for internal
> caching purposes.  99% of the time I cache them because my objects are
> practically immutable, and $this->foo ??= whatever is an easy enough
> pattern.  (If they're not cached then it would be a virtual property, which
> we're not dealing with for now.)  As long as you're caching it in that
> fashion, the write-once-ness still ends up respected.
> >
> > Honestly, Nick tried to come up with examples yesterday while we were
> talking that would not fit into one of those two categories, and for every
> one of them my answer was "if your code is already that badly designed,
> there's nothing we can do for you." :-)
>
> It's nice to hear that there are no other usecases for hooks on readonly
> properties, since this means that we can just allow the 'set' hook and
> add an 'init' hook for the lazy computation use-case without needing to
> violate the semantics of `readonly` by allowing a `get` hook.
>
> > An init hook would be clearer, certainly, though it also has its own
> edge cases.  Can you set something that has an init hook?  What happens if
> there's both a get and init hook?  These probably have answers that could
> be sorted out, but that's a different question from "why the <censored>
> does a readonly class forbid me using even rudimentary hooks???"
>
> Not clearer. It would be the only thing that is semantically sound.
> While it certainly needs careful consideration of semantics to ensure
> there are no edge cases, figuring this out should be much easier than
> intentionally introducing edge cases via a get hook.
>
> As to your questions: The init hook is triggered when reading from a
> property that is in the uninitialized state. The return value of the
> hook is stored in the property and returned as the result of the read
> operation. Having an init hook implies the property is non-virtual.
>
> - Yes, you can set something that has an init hook. Setting means that
> the property will no longer be uninitialized, which means that the init
> hook will no longer be called.
> - If there is both a get and an init hook, the init hook will be called
> when the backing store is uninitialized. The result of the init hook
> will then also go through the get hook. On subsequent reads only the get
> hook will be called.
>
> Best regards
> Tim Düsterhus
>


Hi Tim,

The problem with allowing only set hooks is that readonly class won't be
compatible with hooks, I think that is one of the main motivations behind
this RFC.




Faizan Akram Dar
faizanakram.me

Reply via email to