On Sun, Jul 20, 2025, at 19:18, Eric Norris wrote: > Hi Rob, > > I'm going to respond to a few points from earlier emails here instead > of each one. > > On Sat, Jul 19, 2025 at 6:13 AM Rob Landers <rob@bottled.codes> wrote: > > > > > > > > On Sat, Jul 19, 2025, at 12:09, Claude Pache wrote: > > > > > > > > Le 19 juil. 2025 à 09:46, Rob Landers <rob@bottled.codes> a écrit : > > > > > > > > On Sat, Jul 19, 2025, at 03:04, Claude Pache wrote: > > > > > > > > > > Le 19 juil. 2025 à 00:41, Rob Landers <rob@bottled.codes> a écrit : > > > > > > The original author (Nikita) suggested that there's nothing in the original > > design that precludes accessors -- and highlights languages where there are > > both and they are doing just fine more than 5 years later. > > > > > > Hi Rob, > > > > It is indeed entirely reasonable to have both readonly properties and > > hooked properties (aka accessors), and today PHP has indeed both of them > > (and even asymmetric visibility on top of that, as a separate feature > > contrarily to C#). But it doesn’t mean that it is reasonable for the *same* > > property to be *both* readonly and hooked, which is the point that is > > currently disputed. — What do the other languages allow? Is it possible to > > define a readonly property with a user-defined getter? (Disclaimer: Even if > > one of them allows such a thing, I’ll still think that it is a bad idea.) > > I do not believe I was cherry picking; I share Claude's interpretation > here that the RFC says that readonly doesn't prevent the language from > adopting accessors (hooks) later, which is what the language did, and > notably it did without applying them to readonly properties. > > Could you perhaps walk me through your thinking when the RFC claims > that `assert($prop === $prop2)` "always holds"?
Hi Eric, I think that is explaining how Nikita arrived at some of the conclusions (it is in the rationale section, after all) and shouldn't be taken as literal. Here are some snippets that I think should be looked at a little more closely, that seem to align with the vision of the feature, in the context of getters/setters: "The closest alternative is to declare the property private, and only expose a public getter" -- indicates to me that a single public getter should, in fact, be considered readonly. "Support for first-class readonly properties allows you to directly expose public readonly properties, without fear that class invariants could be broken through external modification" -- indicates to me that interior mutability (and maybe nondeterminism) should be at the discretion of the interior, not the exterior contract. "...readonly properties do not preclude interior mutability. Objects (or resources) stored in readonly properties may still be modified internally" -- further specifies that interior mutability is allowed; only exterior mutability isn't. It doesn't define "interior mutability" stringently, so we can have differing opinions on that; but it seems to be "the value inside the property" which may or may not be an object, resource, or a hook's result. > > > > > —Claude > > > > > > Hey Claude, > > > > From what I've seen in other languages, this combination is fairly common > > and not inherently poblematic. > > > > - C# allows get hooks with user-defined logic, even in readonly structs. > > - Kotlin uses val with a get() body, which is readonly from the consumer's > > perspective, even though the value is computed. > > - TypeScript allows a get-only accessor which acts readonly. > > - Swift also allows get-only computed accessors/hooks. > > (disclaimer, I am not a C# expert) > > It seems that C# has both fields and properties, and a readonly field > seems to align with what a few of us are claiming is how PHP readonly > properties should work. C# properties are more open-ended, and don't > actually support the readonly keyword - you can make them "read only" > in the sense of only having a get accessor (and you can mark that > accessor itself as readonly), but this is different from readonly > fields, which enforce a contract about the mutability of the field. > > I think that C# fields, both readonly and not, match PHP's properties > without hooks. C# properties - which I believe cannot be *marked* > readonly, but they can be *made* read only, i.e. only exposing a get > accessor - match PHP's properties with hooks. I would prefer to simply allow specifying a class as readonly so long as only get hooks are present. However, I'm ok with saying that get hooks may themselves be readonly which accomplishes the same thing and is easier to reason about. > > > > > > > Hi Rob, > > > > The main problem is that we don’t agree on the meaning of “readonly > > property”. > > I agree with Claude here. Rob, I'm curious how you interpret the > contract of readonly. Do you think that it is a contract about > writability to consumers of the class? In an earlier email, you said: > > > In the example above, there is nothing mutable about it. It is "read only" > > from a public contract point-of-view, we just can't mark it as a readonly > > class. > > In this most recent email, you said: > > > The error you get when trying to modify the "get-only accessor" is `Error: > > Cannot assign to 'name' because it is a read-only property` > > > > Thus, readonly is implied by the get-only accessor, there's no need to > > specify it directly. > > Would you say this is how you are interpreting readonly? That it is a > contract to consumers of the class that they can read but cannot write > to it? That's the definition in the RFC, from my reading of it: the ability to expose bare properties without worrying that someone else will modify it. One might argue that there really isn't a reason for readonly anymore, since we have aviz + hooks. Or rather, that readonly could be just a shorthand for that -- plus the ability to write to those properties exactly-once. I suspect this is where "write-once" is coming from elsewhere in the thread, since that is the only difference between "manual readonly" and "engine-powered readonly". > > (including a snippet from an earlier email) > > > I think an init hook is out of the question for 8.5, so I'm not even sure > > it's worth discussing. > > I don't agree that it's not worth discussing alternative solutions to > the problems the RFC authors intend to solve. I think it has been > expressed elsewhere, but I believe we should take the time to make the > best decisions for the language and not rush to add a controversial > feature. Would an init hook actually solve it though? An init hook would basically just be a constructor / default value outside of the constructor that specifies an instance-level constant. The readonly property RFC goes into some details here: "As the default value counts as an initializing assignment, a readonly property with a default value is essentially the same as a constant, and thus not particularly useful. The notion could become more useful in the future, if new expressions are allowed as property default values. At the same time, depending on how exactly property initialization would work in that case, having a default value on a readonly property could preclude userland serialization libraries from working, as they would not be able to replace the default-constructed object. Whether or not this is a concern depends on whether the property is initialized at time of object creation, or as an implicit part of the constructor (or similar). As these are open questions, the conservative choice is to forbid default values until these questions are resolved." When would the init hook get called? And in what order? This brings back some memories of solving some Java language bugs where static variables wouldn't be initialized in time (they're non-deterministic) causing strange crashes, or the potential to "deadlock" yourself and you need to read properties in a specific order in order to ensure the object gets initialized correctly. This isn't something that can be solved in a few weeks. Someone(s) needs to sit down and think through all the possibilities and then create a definition of an init hook that is better than a constructor. — Rob