[RFC] [PROPOSAL] Immutable/final/readonly properties

  108571
February 14, 2020 13:22 kocsismate90@gmail.com (=?UTF-8?B?TcOhdMOpIEtvY3Npcw==?=)
Hi Internals,

I'd like to propose the idea of adding support for immutable/final/readonly
properties in PHP 8.

My plan is to add a new immutable/final/readonly (the name is up for
debate) property modifier to the language so that these kind of properties
could only be initialized but not modified afterwards. Unlike how final
properties in Java work, I think it would be beneficial to allow lazy
initialization of these properties after object construction have taken
place. Currently, I'm in favour of using final or readonly, but not yet
very sure.

I'll write a proper RFC in the following days/week. My clear intent with
final properties is to pave the road for immutable objects for which I have
a POC pull request open (but I haven't pushed all my work yet).

So far, my biggest question (apart from the name) have been how non-typed
properties should behave: as they are implicitly initialized to null if
they don't have an explicit default value (while typed properties remain
uninitialized), further modifications would be impossible to do on them -
which would make non-typed final properties almost useless. Nikita
suggested to just avoid their initialization, but I'd be curious about
other ideas as well.

Thanks,
Máté Kocsis
  108572
February 14, 2020 13:30 ocramius@gmail.com (Marco Pivetta)
On Fri, Feb 14, 2020 at 2:23 PM Máté Kocsis <kocsismate90@gmail.com> wrote:

> > So far, my biggest question (apart from the name) have been how non-typed > properties should behave: as they are implicitly initialized to null if > they don't have an explicit default value (while typed properties remain > uninitialized), further modifications would be impossible to do on them - > which would make non-typed final properties almost useless. Nikita > suggested to just avoid their initialization, but I'd be curious about > other ideas as well. >
Considering that PHP 8 will have union types, adding un-typed properties support seems like a waste of time. If somebody really wants a `mixed` property to be immutable, they could write `private immutable null|bool|int|float|string|array|object $property;`. That would make implementation straightforward, since you'd expect `immutable` to be before a type declaration (can be done in the parser, right?). Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/
  108575
February 14, 2020 13:42 kocsismate90@gmail.com (=?UTF-8?B?TcOhdMOpIEtvY3Npcw==?=)
> > If somebody really wants a `mixed` property to be immutable, they could > write `private immutable null|bool|int|float|string|array|object > $property;`. >
Yeah, one of my ideas was to first add support for mixed (for which there have been a proposal/PR since quite some time), so that all non-typed properties could be implicitly upgraded to the mixed type. But I don't think it's the way to go... Maybe only if our long-term goal would be to deprecate/remove non-typed properties and implicit initialization altogether in favour of mixed type and implicit uninitialization...
> That would make implementation straightforward, since you'd expect > `immutable` to be before a type declaration (can be done in the parser, > right?). >
Yeah, the implementation didn't seem very tricky yet (but people with more experience with the internals of PHP should tell). However, Nikita also warned me not to support references. So this is another question to decide...
  108590
February 14, 2020 23:07 rowan.collins@gmail.com (Rowan Tommins)
On 14/02/2020 13:42, Máté Kocsis wrote:
> Maybe only if our long-term goal would be to deprecate/remove > non-typed properties and implicit initialization altogether in favour of > mixed type and implicit uninitialization...
Can I just leave an "ugh, please no" on this part. I remain of the opinion that the introduction of the "uninitialised" state was a huge mistake, and we should be actively working towards making it unnecessary, not building more features that rely on it. Immutable properties, and eventually immutable objects, however, are something I'd be very interested to see. Regards, -- Rowan Tommins (né Collins) [IMSoP]
  108598
February 15, 2020 14:34 kocsismate90@gmail.com (=?UTF-8?B?TcOhdMOpIEtvY3Npcw==?=)
Hi Rowan,

I'm also on the opinion that making the mixed type the (implicit) default
is not a good idea.

However, I believe the uninitialized state is useful, what's more, it was
unavoidable
in order to properly support non-nullable object properties. But I don't
want to make
a case for this decision as it's too late now. :)

> Immutable properties, and eventually immutable objects, however, are something I'd be very interested to see.
I am happy to hear! Máté Kocsis .. Rowan Tommins collins@gmail.com> ezt írta (időpont: 2020. febr. 15., Szo, 0:07):
> On 14/02/2020 13:42, Máté Kocsis wrote: > > Maybe only if our long-term goal would be to deprecate/remove > > non-typed properties and implicit initialization altogether in favour of > > mixed type and implicit uninitialization... > > > Can I just leave an "ugh, please no" on this part. I remain of the > opinion that the introduction of the "uninitialised" state was a huge > mistake, and we should be actively working towards making it > unnecessary, not building more features that rely on it. > > > Immutable properties, and eventually immutable objects, however, are > something I'd be very interested to see. > > > Regards, > > -- > Rowan Tommins (né Collins) > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
  108592
February 15, 2020 08:18 larry@garfieldtech.com ("Larry Garfield")
On Fri, Feb 14, 2020, at 7:22 AM, Máté Kocsis wrote:
> Hi Internals, > > I'd like to propose the idea of adding support for immutable/final/readonly > properties in PHP 8. > > My plan is to add a new immutable/final/readonly (the name is up for > debate) property modifier to the language so that these kind of properties > could only be initialized but not modified afterwards. Unlike how final > properties in Java work, I think it would be beneficial to allow lazy > initialization of these properties after object construction have taken > place. Currently, I'm in favour of using final or readonly, but not yet > very sure. > > I'll write a proper RFC in the following days/week. My clear intent with > final properties is to pave the road for immutable objects for which I have > a POC pull request open (but I haven't pushed all my work yet). > > So far, my biggest question (apart from the name) have been how non-typed > properties should behave: as they are implicitly initialized to null if > they don't have an explicit default value (while typed properties remain > uninitialized), further modifications would be impossible to do on them - > which would make non-typed final properties almost useless. Nikita > suggested to just avoid their initialization, but I'd be curious about > other ideas as well. > > Thanks, > Máté Kocsis
My concern is that a simple read-only/final "flag" is a very limited feature set. I'd still love for us to revisit property accessors at some point (if the performance issues could be resolved), and I fear that layering that *and* a read-only flag together would result in... much complex weirdness. (Technical term.) That said, were such a feature to be added, I would strongly recommend making them able to be defined in terms of an expression, or possibly a callable/anon function, with no explicit setting allowed. To wit: class Foo { protected string $firstName; protected string $lastName; protected function getFullName() { return $this->firstName . $this->lastName; } // And then one of these options: public final string $fullName = $this->firstName . $this->lastName; public final string $fullName = fn() => $this->firstName . $this->lastName; public final string $fullName = $this->getFullName(); } That would allow for their complete definition in one location, make it clear how they're derived, etc. They essentially become an auto-memoizing method (which suits me just fine). Their value would potentially change depending on when it's first called depending on the other values in the object, but that's no different than if they were simply "set" from an arbitrary location. The potential for unpredictable semi-non-determinism is the same, or possibly better this way. (In that case, "final" or "lazy" or "locked" would be reasonable names; read-only and immutable are misleading, as it's really write-once, not read-only, not truly immutable. I suppose then an "immutable object" would be one in which all properties are either final/lazy/locked or set by the constructor only.) There was a thread a few weeks ago on "lazily derived constants" that probably has some interesting thoughts as well, though of course this would be property-like syntax, which is fine. As for references and untyped final properties... Just don't go there. Require a final property to be non-reference and typed. I do not foresee untyped properties ever going away (too much legacy code, plus they are legit useful at times), but that doesn't mean every conceivable property variant ever needs to support them. Requiring that a final property be typed non-reference seems entirely reasonable to me. --Larry Garfield
  108596
February 15, 2020 14:24 kocsismate90@gmail.com (=?UTF-8?B?TcOhdMOpIEtvY3Npcw==?=)
Hi Larry,

I admit that this flag is not too interesting, but I believe it still has
its own merit. I can imagine that the flag could play well with property
accessors as well, however,
in my opinion, the main use-case of final properties generally doesn't
involve setters/set accessors.

> In that case, "final" or "lazy" or "locked" would be reasonable names; read-only and immutable are misleading, as it's really write-once, not
read-only, not truly immutable. In the meanwhile, I realized that - "immutable" is simply not true in case of resource and (non-immutable) object properties - "readonly" is probably somewhat better, but still not always true in case of lazy initialization - "final" seems ok, but it would probably be a better fit for a feature that would prevent a property to be overwritten (similarly to "final" for methods) So I think "final" should only be chosen if we don't want to restrict property overwriting later. Otherwise, we could use also "locked" or "sealed" (inspiring from C#).
> As for references and untyped final properties... Just don't go there. Require a final property to be non-reference and typed.
So it's essentially what Marco also suggested... Unfortunately, I didn't exactly get the idea first (I focused too much on the mixed type), but restricting final to typed properties now seems reasonable. :) But let me collect the possibilities that I've thought about so far: - do not implicitly initialize untyped final properties: although I liked this idea first, now it feels a bit unintuitive - add support for mixed, and implicitly convert untyped final properties to this type: unintuitive - require final properties to be explicitly initialized before object instantiation finishes: complicated, makes lazy initalization/proxying difficult/impossible - require final properties to be typed: looks straightforward
> I do not foresee untyped properties ever going away
Although I tend to declare types everywhere I can, I also believe we should leave gradual typing intact. Thank you very much for the feedback! Máté Kocsis Larry Garfield <larry@garfieldtech.com> ezt írta (időpont: 2020. febr. 15., Szo, 9:18):
> On Fri, Feb 14, 2020, at 7:22 AM, Máté Kocsis wrote: > > Hi Internals, > > > > I'd like to propose the idea of adding support for > immutable/final/readonly > > properties in PHP 8. > > > > My plan is to add a new immutable/final/readonly (the name is up for > > debate) property modifier to the language so that these kind of > properties > > could only be initialized but not modified afterwards. Unlike how final > > properties in Java work, I think it would be beneficial to allow lazy > > initialization of these properties after object construction have taken > > place. Currently, I'm in favour of using final or readonly, but not yet > > very sure. > > > > I'll write a proper RFC in the following days/week. My clear intent with > > final properties is to pave the road for immutable objects for which I > have > > a POC pull request open (but I haven't pushed all my work yet). > > > > So far, my biggest question (apart from the name) have been how non-typed > > properties should behave: as they are implicitly initialized to null if > > they don't have an explicit default value (while typed properties remain > > uninitialized), further modifications would be impossible to do on them - > > which would make non-typed final properties almost useless. Nikita > > suggested to just avoid their initialization, but I'd be curious about > > other ideas as well. > > > > Thanks, > > Máté Kocsis > > My concern is that a simple read-only/final "flag" is a very limited > feature set. I'd still love for us to revisit property accessors at some > point (if the performance issues could be resolved), and I fear that > layering that *and* a read-only flag together would result in... much > complex weirdness. (Technical term.) > > That said, were such a feature to be added, I would strongly recommend > making them able to be defined in terms of an expression, or possibly a > callable/anon function, with no explicit setting allowed. To wit: > > class Foo { > > protected string $firstName; > protected string $lastName; > > protected function getFullName() { return $this->firstName . > $this->lastName; } > > // And then one of these options: > > public final string $fullName = $this->firstName . $this->lastName; > > public final string $fullName = fn() => $this->firstName . > $this->lastName; > > public final string $fullName = $this->getFullName(); > } > > That would allow for their complete definition in one location, make it > clear how they're derived, etc. They essentially become an auto-memoizing > method (which suits me just fine). Their value would potentially change > depending on when it's first called depending on the other values in the > object, but that's no different than if they were simply "set" from an > arbitrary location. The potential for unpredictable semi-non-determinism > is the same, or possibly better this way. > > (In that case, "final" or "lazy" or "locked" would be reasonable names; > read-only and immutable are misleading, as it's really write-once, not > read-only, not truly immutable. I suppose then an "immutable object" would > be one in which all properties are either final/lazy/locked or set by the > constructor only.) > > There was a thread a few weeks ago on "lazily derived constants" that > probably has some interesting thoughts as well, though of course this would > be property-like syntax, which is fine. > > As for references and untyped final properties... Just don't go there. > Require a final property to be non-reference and typed. I do not foresee > untyped properties ever going away (too much legacy code, plus they are > legit useful at times), but that doesn't mean every conceivable property > variant ever needs to support them. Requiring that a final property be > typed non-reference seems entirely reasonable to me. > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >