[RFC] Property write visibility

  110768
June 29, 2020 09:41 andre.romcke@gmail.com (=?UTF-8?B?QW5kcsOpIFLDuG1ja2U=?=)
Good morning Internals,

I'd like to start discussion on a new RFC proposing a way to be able to
(optionally) specify property
write visibility, separate from read:

https://wiki.php.net/rfc/property_write_visibility

This enables readonly, write-only and immutable like semantics for PHP's
properties.

These are the common use cases where users tend to resort to magic methods
or setter/getter
methods. This proposal will as such avoid unnecessary boilerplate, makes
coding easier and more
ergonomic, and in the case of magic method usage improve performance.


Best,
André Rømcke
  110769
June 29, 2020 10:00 maxsem.wiki@gmail.com (Max Semenik)
On Mon, Jun 29, 2020 at 12:42 PM André Rømcke romcke@gmail..com>
wrote:

> This enables readonly, write-only and immutable like semantics for PHP's > properties. >
I agree that there is a use case for it, however I don't think the proposed syntax `public:private` is intuitive. Maybe we can come up with something better? -- Best regards, Max Semenik
  110770
June 29, 2020 10:06 deleugyn@gmail.com (Deleu)
I don't dislike the syntax and I think I can get used to it extremely fast,
tbh. Are there any other languages that have a similar syntax? Has any
other language syntax been considered?

On Mon, Jun 29, 2020 at 12:01 PM Max Semenik wiki@gmail.com> wrote:

> On Mon, Jun 29, 2020 at 12:42 PM André Rømcke romcke@gmail.com> > wrote: > > > This enables readonly, write-only and immutable like semantics for PHP's > > properties. > > > > I agree that there is a use case for it, however I don't think the proposed > syntax `public:private` is intuitive. Maybe we can come up with something > better? > > > -- > Best regards, > Max Semenik >
-- Marco Aurélio Deleu
  110772
June 29, 2020 10:52 andre.romcke@gmail.com (=?UTF-8?B?QW5kcsOpIFLDuG1ja2U=?=)
man. 29. jun. 2020 kl. 12:06 skrev Deleu <deleugyn@gmail.com>:
> Are there any other languages that have a similar syntax? Has any other language syntax been considered
The only one I could find that matches is Swift: public private(set) var numberOfEdits = 0 https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html#ID18 Beyond that there are some notable related examples: C# public readonly Color Black = new Color(0, 0, 0); The semantics of readonly is closer to what we refer to as immutable here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#readonly-fields If you want other semantics in C# you'll need to resort to Accessors: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#accessors Rust: // This field can be read (but not written) by super. #[readonly] pub(super) readable: i32, Essentially a feature using "attributes": https://docs.rs/readonly/0.1.6/readonly/ -- Best André Rømcke
  110777
June 29, 2020 14:13 andre.romcke@gmail.com (=?UTF-8?B?QW5kcsOpIFLDuG1ja2U=?=)
> > >> I agree that there is a use case for it, however I don't think the > proposed syntax `public:private` is intuitive. Maybe we can come up with > something better? >
Would something closer to Swift be better? If so I expanded the RFC with that syntax option as well: class User { public private(set) int $id; public protected(set) string $name; public function __construct(int $id, string $name) { $this->id = $id; $this->name = $name; }}
  110778
June 29, 2020 14:22 marandall@php.net (Mark Randall)
On 29/06/2020 15:13, André Rømcke wrote:
> Would something closer to Swift be better? If so I expanded the RFC with > that syntax option as well:
Borrowing from the various accessors RFCs: public int $x { protected set; protected unset; } Then a future RFC can build upon it by adding the override functions while keeping the same base syntax. Mark Randall
  110776
June 29, 2020 14:10 marandall@php.net (Mark Randall)
On 29/06/2020 10:41, André Rømcke wrote:

I'd like this feature as a stop-gap for accessors.

However, I don't like the syntax at all, I couldn't reasonably vote for 
it in its current suggested state. I think it's just too messy.

I'm not sure what the alternative should be though. It seems like the 
accessor syntax would be the only long-term clean way.

Mark Randall
  110782
June 29, 2020 15:44 ocramius@gmail.com (Marco Pivetta)
Hey André,

This does indeed seem to cut into the traditional property accessors scope.

I'm no longer seeing a reason to have property accessors, since immutable
state (and promotion thereof) is much more relevant to fight bugs and
improve application performance and maintainability.

Therefore, I would endorse re-visiting the RFC at
https://wiki.php.net/rfc/write_once_properties instead.

Máté also linked today (
https://twitter.com/kocsismate90/status/1277625002720968704) that C# 9.0 is
getting init-only properties, which looks similar to the RFC linked above.

Assuming we solve annoyances around cloning, that would be a more sensible
way forward, while property accessors seem to perpetuate the bad practice
of getters and setters, which are the main cause for me having to fire up a
debugger in any environment.

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/


On Mon, Jun 29, 2020 at 11:42 AM André Rømcke romcke@gmail..com>
wrote:

> Good morning Internals, > > I'd like to start discussion on a new RFC proposing a way to be able to > (optionally) specify property > write visibility, separate from read: > > https://wiki.php.net/rfc/property_write_visibility > > This enables readonly, write-only and immutable like semantics for PHP's > properties. > > These are the common use cases where users tend to resort to magic methods > or setter/getter > methods. This proposal will as such avoid unnecessary boilerplate, makes > coding easier and more > ergonomic, and in the case of magic method usage improve performance. > > > Best, > André Rømcke >
  110783
June 29, 2020 16:19 rowan.collins@gmail.com (Rowan Tommins)
On Mon, 29 Jun 2020 at 16:44, Marco Pivetta <ocramius@gmail.com> wrote:

> property accessors seem to perpetuate the bad practice > of getters and setters >
Outside of access restrictions, a common use case I've seen for property accessors is lazy-loading, which I know is something you use in other forms..
> Máté also linked today ( https://twitter.com/kocsismate90/status/1277625002720968704) that C# 9.0 is
getting init-only properties, which looks similar to the RFC linked above. Note that in C# the new "init" keyword is explicitly an extension of property accessors [1], and relates specifically to "object initializers", which PHP does not have; a proposal for them last year [2] was rejected. An existing "readonly" keyword [3] allows you to write a variable only in the constructor, and "init" is mostly needed because object initializers are run too late for this. C# 9.0 also has a bunch of features around immutable data structures in general, including a variant of object initializers called "with-expressions" [4] to solve the "modified clone" problem. [1] https://github.com/dotnet/csharplang/blob/master/proposals/init.md#detailed-design [2] https://wiki.php.net/rfc/object-initializer [3] https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly [4] https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/#with-expressions -- Rowan Tommins [IMSoP]
  110784
June 29, 2020 16:21 ocramius@gmail.com (Marco Pivetta)
Hey Rowan,

On Mon, Jun 29, 2020, 18:19 Rowan Tommins collins@gmail.com> wrote:

> On Mon, 29 Jun 2020 at 16:44, Marco Pivetta <ocramius@gmail.com> wrote: > > > property accessors seem to perpetuate the bad practice > > of getters and setters > > > > > Outside of access restrictions, a common use case I've seen for property > accessors is lazy-loading, which I know is something you use in other > forms. >
I had already tested the write-once properties RFC with lazy-loading: works just fine 👍
>
  110787
June 29, 2020 17:58 rowan.collins@gmail.com (Rowan Tommins)
On 29/06/2020 17:21, Marco Pivetta wrote:
> Hey Rowan, > > On Mon, Jun 29, 2020, 18:19 Rowan Tommins collins@gmail.com > <mailto:rowan.collins@gmail.com>> wrote: > > On Mon, 29 Jun 2020 at 16:44, Marco Pivetta <ocramius@gmail.com > <mailto:ocramius@gmail.com>> wrote: > > > property accessors seem to perpetuate the bad practice > > of getters and setters > > > > > Outside of access restrictions, a common use case I've seen for > property > accessors is lazy-loading, which I know is something you use in > other forms. > > > I had already tested the write-once properties RFC with lazy-loading: > works just fine 👍 >
I meant that property accessors can be used to implement lazy-loading, removing the need for magic methods and dynamic references to variables, e.g.: class Whatever {     private string $_name;     public string $name {          get {              if( ! isset($_name) ) { $this->loadData(); }              return $this->_name;          }     } } Regards, -- Rowan Tommins (né Collins) [IMSoP]
  110786
June 29, 2020 17:04 nicolas.grekas+php@gmail.com (Nicolas Grekas)
> > I'd like to start discussion on a new RFC proposing a way to be able to > (optionally) specify property > write visibility, separate from read: > > https://wiki.php.net/rfc/property_write_visibility > > This enables readonly, write-only and immutable like semantics for PHP's > properties. > > These are the common use cases where users tend to resort to magic methods > or setter/getter > methods. This proposal will as such avoid unnecessary boilerplate, makes > coding easier and more > ergonomic, and in the case of magic method usage improve performance. >
Thanks, André, I really like it. I feel like it perfectly fits the runtime visibility model of PHP. The RFC could have some words to tell how this would behave when considering the existing magic accessors. We should also define the behavior when creating a reference (write access should be granted, isn't it?) and when unsetting a property. I'd like to share three more points to the discussion: 1. The previous RFC(s) shocked on a conflict between purity declarations (immutable/readonly) and the effective need for mutability in e.g. cloning operations. My experience in PHP is that keywords are strong guidelines but should never be hard blockers: PHP is a runtime scripting language and some of its power and flexibility comes from that, e.g. being able to use reflection sometime to read/write a property in a "friend" scope. "final" is the canonical contra-example of an imperative keyword that blocks legit use cases (e.g. inheritance proxies) I understand why some ppl want immutable/readonly hard guarantees. I think those are nice goals, and I also think that they are better solved by attributes/annotations. These features fit compiled languages. In PHP, they fit static analyzers. There are great ones already and they do a really good job. 2. In other answers, I'm seeing questions about private(isset)/private(unset) in addition to just read+write dissociation. I'm not sure this makes sense: once a property is declared, "isset-accessibility" is fully covered by "read-accessibility". Same for "unset-accessibility": it's included in "write-accessibility". Clarifying how magic accessors would work in the RFC should help solve this branch of the discussion. 3. About accessors, they look like another topic to me. I'm not seeing the need for accessors at all actually. You might disagree, but my point is: that's another topic. We don't need to agree on the usefulness of accessors to decide that this RFC provides actionable value that would benefit the ecosystem. Being able to enforce an externally-immutable-but-internally-mutable state is already a lot of value, I know where I would leverage it immediately. About the syntax, the proposed one looks quite effective to me. It's new, we need to get used to it. This should come fast given how simple it is. TL;DR, I fully support the RFC :) Nicolas
  110788
June 29, 2020 19:54 d.h.j.takken@freedom.nl (Dik Takken)
On 29-06-2020 11:41, André Rømcke wrote:
> Good morning Internals, > > I'd like to start discussion on a new RFC proposing a way to be able to > (optionally) specify property > write visibility, separate from read: > > https://wiki.php.net/rfc/property_write_visibility
Perhaps another option could be to use attributes: <> public int $id; Assuming named arguments get accepted as well, we could use optional arguments to specify special behavior by writing: <> public int $id; These optional arguments could also be introduced later using a followup RFC, after introducing a basic ReadOnly attribute. This attribute-based approach could be extended later to implement property accessors. That would provide property accessors similar to how it is done in Python: <> public function someValue(): int { return $this->someValue; } which could then be accessed as: $instance->someValue The above accessor method would be the equivalent of: <> public int $someValue; That makes the ReadOnly attribute a short hand for the Property attribute. This short hand is something that Python does not have, by the way. Using accessor attributes to create a writable property could look like this: <> public function someValue(int $newValue) { $this->someValue = $newValue; } Making the property writable only in the protected or private scope could be done by using the existing mechanism of declaring the accessor method as protected or private. So perhaps an attribute-based approach provides a nice alternative path for gradually improving object ergonomics. Regards, Dik Takken
  110794
June 30, 2020 12:46 andre.romcke@gmail.com (=?UTF-8?B?QW5kcsOpIFLDuG1ja2U=?=)
> Perhaps another option could be to use attributes: > > <> > public int $id;
I’d actually also like a syntax like that as well for ReadOnly and Immutable in the end. It's more readable and it would be possible to annotate on the class level as well (to affect all properties). So I initially explored* in this direction, however if we go that way first we'll likely end up with any reflection code having to deal with attributes and understand their underlying visibility semantics. If we rather go this route of first introducing the concept of disconnected visibility. The reflection API is far clearer / understandable, more future proof, and adding the attributes as immediate syntax sugar followup is far more straightforward. * initial explorative draft rfc: https://wiki.php.net/rfc/readonly_and_immutable_properties
  110791
June 30, 2020 07:47 someniatko@gmail.com (someniatko)
I do agree with Marco that this is a step in a wrong direction. Our
goal should be not ensuring that a prop is not rewritten outside, but
rather that it is not re-written at all. It makes no sense to rewrite
a property in majority of cases:
1. fields of an DTO - nay. Should be immutable instead. You never
change DTO, don't you?
2. injected services (like DB connection or an HTTP client) - nay.
Shouldn't ever be overwritten once an object containing them is
instantiated. Write-once / immutable is preferred.
3. data fields of an Entity-like object - looks like the only
reasonable case. However adding dedicated syntax for this is arguably
not much better that what we have now. It is already solvable with
standard getX() pattern, or with a single method returning a required
chunk of state as DTO.

So for me this does only solve the problem of having getters (or
dedicated methods) in #3, which is rare enough compared to other code,
and is already solvable with syntax existing nowadays already.
Introducing the new syntax, however, will have the following
downsides:
- adding proper immutable / write-once properties to the language will
be met with much more resistance: "Why adding immutable if we have
private set already!"
- this will encourage using them in places where immutability (e.g.
via static analysis tool like Psalm) should be used instead (see #1
and #2).
- adding more advanced property accessors feature will be also likely
met with more resistance.
  110792
June 30, 2020 07:59 nikita.ppv@gmail.com (Nikita Popov)
On Mon, Jun 29, 2020 at 11:43 AM André Rømcke romcke@gmail..com>
wrote:

> Good morning Internals, > > I'd like to start discussion on a new RFC proposing a way to be able to > (optionally) specify property > write visibility, separate from read: > > https://wiki.php.net/rfc/property_write_visibility > > This enables readonly, write-only and immutable like semantics for PHP's > properties. > > These are the common use cases where users tend to resort to magic methods > or setter/getter > methods. This proposal will as such avoid unnecessary boilerplate, makes > coding easier and more > ergonomic, and in the case of magic method usage improve performance. >
I think this is a good direction to explore, but would recommend delaying it until PHP 8.1. As the RFC and discussion note, the design space here overlaps significantly with both readonly/immutability and property accessors. We should take enough time to consider these alternatives/extensions as well, to ensure that we don't end up with multiple distinct and possibly incompatible mechanisms. We don't have that time before PHP 8.0 feature freeze. Regards, Nikita
  110793
June 30, 2020 11:25 Danack@basereality.com (Dan Ackroyd)
On Mon, 29 Jun 2020 at 10:42, André Rømcke romcke@gmail.com> wrote:
> > I'd like to start discussion on a new RFC proposing a way to be able to > (optionally) specify property > write visibility, separate from read: > > https://wiki.php.net/rfc/property_write_visibility >
From the RFC: "Attempting to pass a property value outside of allowed writable scope as a reference, results in an error." This part could probably do with having some details for it. Also, any implementation of that rule might need to be checked for performance issues. cheers Dan Ack
  110798
July 1, 2020 10:44 nikita.ppv@gmail.com (Nikita Popov)
On Tue, Jun 30, 2020 at 1:26 PM Dan Ackroyd <Danack@basereality.com> wrote:

> On Mon, 29 Jun 2020 at 10:42, André Rømcke romcke@gmail.com> wrote: > > > > I'd like to start discussion on a new RFC proposing a way to be able to > > (optionally) specify property > > write visibility, separate from read: > > > > https://wiki.php.net/rfc/property_write_visibility > > > > From the RFC: > "Attempting to pass a property value outside of allowed writable scope > as a reference, results in an error." > > This part could probably do with having some details for it. > > Also, any implementation of that rule might need to be checked for > performance issues. >
I think it would be technically possible, by extending the existing mechanism for references to typed properties. However, we definitely shouldn't do this, because it goes against existing language semantics. You can take a reference to a normal private property (i.e. private get, private set), pass it outside the class and then modify it. It would be inconsequent to assign stricter semantics to a weaker visibility requirement (public get, private set). Regards, Nikita
  110799
July 1, 2020 10:58 andre.romcke@gmail.com (=?utf-8?Q?Andr=C3=A9_R=C3=B8mcke?=)
>> "Attempting to pass a property value outside of allowed writable scope >> as a reference, results in an error." > > ... we definitely shouldn't do this, because it goes against existing language semantics. You can take a reference to a normal private property (i.e. private get, private set), pass it outside the class and then modify it.
This was copied from some other source actually. I’m all for staying as close as possible to how the language behaves on this, changing it should be different RFC. Should I just remove this section or do you have suggestions for what we need to specify when it comes references?
  110800
July 1, 2020 12:35 nikita.ppv@gmail.com (Nikita Popov)
On Wed, Jul 1, 2020 at 12:58 PM André Rømcke romcke@gmail.com> wrote:

> > "Attempting to pass a property value outside of allowed writable scope >> as a reference, results in an error." > > > ... we definitely shouldn't do this, because it goes against existing > language semantics. You can take a reference to a normal private property > (i.e. private get, private set), pass it outside the class and then modify > it. > > > > This was copied from some other source actually. I’m all for staying as > close as possible to how the language behaves on this, changing it should > be different RFC. > > Should I just remove this section or do you have suggestions for what we > need to specify when it comes references? >
I think the only thing worth mentioning where references are concerned is that "$x =& $this->prop" is considered a write of $this->prop, not a read, so it is subject to the write visibility. But once the reference is acquired, visibility no longer factors into the behavior. Nikita