Re: [PHP-DEV] Re: [RFC] Object Initializer

This is only part of a thread. view whole thread
  107171
September 16, 2019 14:37 michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=)
Hi Rowan,

pon., 16 wrz 2019 o 15:47 Rowan Tommins collins@gmail.com>
napisał(a):

> On Mon, 16 Sep 2019 at 08:29, Michał Brzuchalski < > michal.brzuchalski@gmail.com> wrote: > > > Please keep in mind that initializing properties through object > initializer > > applies to visible properties and is possible to assign > > protected or private properties from the class scope as well. > > > > > The problem with that is that you need an extra static method to make use > of it, and you still need to get the arguments into that method. It might > be useful occasionally, but it still doesn't help constructors which are > setting a large number of private / protected properties. > > This RFC is not trying to help those constructors but tries to simplify
instantiation objects and initializing properties there where any kind of constructor won't help, but rather would be unnecessary at all. The proposed solution applies well in DTO, "structs" etc. where you need to deal with 15+ properties which don't need any other validation than types and those are completely valid uses of public properties.
> > > I don't see the reasons why many of you consider public properties a bad > > solution. PHP language has support for public properties > > and with typed properties, it is possible to ensure valid object state > > using VO's which are valid all the time, consider Uuid userland > > implementation > > no one checks if that's valid UUID, cause it's ensured by VO. > > > > > Firstly, it's not necessarily a case of "considering public properties a > bad solution"; it's about evaluating where the new feature could be used, > and where it wouldn't help. If there was a feature which helped this use > case *and* other use cases, I think that would be "better", but that > doesn't make this feature "bad". > > Secondly, typed properties certainly make public properties more appealing, > but there are still a bunch of things that you can't do with them, like > declaring them readonly, or having logic other than type validation in > getters and setters. Note that C#, which has object initializers, also has > these features, making them a lot more powerful. > > True, C# which ships with object initializers also having property
accessors, read-only etc. There are RFC's treating about named arguments, property accessors showing up occasionally on ML. But none of them was accepted. This is another feature and another talk. There is no RFC's which tries to solve all those issues in one big RFC, as such chances of success would be very low.
> > > Any kind of features like promoting arguments from the constructor or > named > > arguments are fine but not efficient in those cases. > > Any good practices suggest limiting function|method arguments while the > > case is where there is a significant amount of properties > > to be initialized and additionally which don't need any kind of > validation > > due to VO, or simple scalars. > > > > > > That's a good point; named parameters make function calls scale much better > to long lists of parameters, but *declaring* the constructor would still be > unwieldy. The only way to improve that would be for the class to > effectively opt into having an initializer using a special syntax for the > constructor. Larry gave this example syntax: > > Please define long lists of parameters, cause issue this RFC is trying to
solve is a simplification and ensuring properly initialized state of all required and visible properties and we talk here about DTO's like classes with tons of properties. You wouldn't want to put 15+ arguments in your constructor to initialize public properties which don't need other validation than proper type, right? Even if it would be just adding "public" keyword in front of them.
> class Employee { > protected int $age; > protected string $name; > protected ?Employee $boss; > > public function hoist __construct() { > if ($age < 18) throw new ChildLaborException(); > } > } > > And Paul M Jones mentioned this version from Hack, where the parameters are > listed in the constructor, but don't need to be re-listed outside it: > > class Employee { > public function __construct( > protected int $age, > protected string $name, > protected ?Employee $boss > ) { > if ($age < 18) throw new ChildLaborException(); > } > } > > > Either of those, with named parameters, would be almost indistinguishable > from object initializers at the call site. Depending on the syntax chosen, > it might be as similar as: > > // Call initializer, requires public properties > new Employee { age => 42, name => 'John Smith' }; > // Call constructor, requires special constructor definition > new Employee( age => 42, name => 'John Smith' ); > > Last RFC treating about named arguments has similar syntax with curly
braces, but all together with previous ones tries to solve the issue through additional syntax inside parentheses, which means both features can coexist together. Calling instantiation always used parentheses as the way to pass constructor arguments let's keep it that way. Using object-initializer would use curly braces - just like it's used to be solved in other languages.
> > That would require multiple new features, though, so initializers might be > more achievable in the short term, and perhaps there is room for both, > particularly if support for getters and setters improves. > > Here again, IIRC you're trying to solve the issue which is off-topic.
Improving protected and private properties initialization through constructor is not the main target of current RFC. Thanks, Michał Brzuchalski
  107172
September 16, 2019 14:57 rowan.collins@gmail.com (Rowan Tommins)
On Mon, 16 Sep 2019 at 15:37, Michał Brzuchalski <michal@brzuchalski.com>
wrote:

> > >> The problem with that is that you need an extra static method to make use >> of it, and you still need to get the arguments into that method. It might >> be useful occasionally, but it still doesn't help constructors which are >> setting a large number of private / protected properties. >> >> > This RFC is not trying to help those constructors but tries to simplify > instantiation objects and initializing properties > there where any kind of constructor won't help, but rather would be > unnecessary at all. >
I realize that, I was responding to a specific point: you said that the syntax would work for protected or private properties if used where those are visible. I was saying that I don't think that combination would be used very often, so it's easiest to just discuss the public property case.
> You wouldn't want to put 15+ arguments in your constructor to initialize > public properties which > don't need other validation than proper type, right? > > Even if it would be just adding "public" keyword in front of them. >
Why not? You've got to list those 15 properties somewhere; if the syntax was such that you only needed to list them once, it makes no difference whether we call the result "class initializer" or "automatic constructor with 15 named parameters", IMO.
> > >> Either of those, with named parameters, would be almost indistinguishable >> from object initializers at the call site. Depending on the syntax chosen, >> it might be as similar as: >> >> // Call initializer, requires public properties >> new Employee { age => 42, name => 'John Smith' }; >> // Call constructor, requires special constructor definition >> new Employee( age => 42, name => 'John Smith' ); >> >> > Last RFC treating about named arguments has similar syntax with curly > braces, but all together with previous ones > tries to solve the issue through additional syntax inside parentheses, > which means both features can coexist together. > > Calling instantiation always used parentheses as the way to pass > constructor arguments let's keep it that way. > Using object-initializer would use curly braces - just like it's used to > be solved in other languages. >
My intention here was just to show that using named parameters would be just as concise as using an object initializer; I just picked a pair of syntaxes that were as similar as possible to illustrate that.
> > >> >> That would require multiple new features, though, so initializers might be >> more achievable in the short term, and perhaps there is room for both, >> particularly if support for getters and setters improves. >> >> > Here again, IIRC you're trying to solve the issue which is off-topic. > Improving protected and private properties initialization through > constructor is not the main target of current RFC. >
I don't think it's off-topic to consider whether a related feature would make this one redundant. However, you've picked a weird sentence to reply to, because I'm agreeing with you, that the two features could exist side by side without being redundant. Regards, -- Rowan Tommins [IMSoP]
  107174
September 16, 2019 15:16 michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=)
Hi Rowan,

pon., 16 wrz 2019 o 16:57 Rowan Tommins collins@gmail.com>
napisał(a):

> > >> >>> >>> That would require multiple new features, though, so initializers might >>> be >>> more achievable in the short term, and perhaps there is room for both, >>> particularly if support for getters and setters improves. >>> >>> >> Here again, IIRC you're trying to solve the issue which is off-topic. >> Improving protected and private properties initialization through >> constructor is not the main target of current RFC. >> > > > > I don't think it's off-topic to consider whether a related feature would > make this one redundant. However, you've picked a weird sentence to reply > to, because I'm agreeing with you, that the two features could exist side > by side without being redundant. >
Sorry for that, the quoted sentence was left unintentionally and yes, it's not off-topic. Had to rethink what I was trying to say, but I do think both these features could exist. Regards, Michał Brzuchalski
  107181
September 16, 2019 21:55 larry@garfieldtech.com ("Larry Garfield")
On Mon, Sep 16, 2019, at 10:16 AM, Michał Brzuchalski wrote:
> Hi Rowan, > > pon., 16 wrz 2019 o 16:57 Rowan Tommins collins@gmail.com> > napisał(a): > > > > > > >> > >>> > >>> That would require multiple new features, though, so initializers might > >>> be > >>> more achievable in the short term, and perhaps there is room for both, > >>> particularly if support for getters and setters improves. > >>> > >>> > >> Here again, IIRC you're trying to solve the issue which is off-topic. > >> Improving protected and private properties initialization through > >> constructor is not the main target of current RFC. > >> > > > > > > > > I don't think it's off-topic to consider whether a related feature would > > make this one redundant. However, you've picked a weird sentence to reply > > to, because I'm agreeing with you, that the two features could exist side > > by side without being redundant. > > > > Sorry for that, the quoted sentence was left unintentionally and yes, it's > not off-topic. > Had to rethink what I was trying to say, but I do think both these features > could exist. > > Regards, > Michał Brzuchalski
I am not sure I agree here. As I noted earlier, we're running out of sigils. Suppose initializer syntax used: new Employee{prop = "val"}; Now later we want to add named parameters. What happens if we use the same syntax? Does it mean the same thing, really? Or does the meaning of that call syntax vary depending on whether the constructor is defined in such a way to make it support named parameters? What happens when it could mean either, but the result would be different? Or do we have to guarantee that the result is the same, even if that means limiting one or the other? That could be avoided by using some other syntax for named parameter calls, say: new Employee({ prop = "val"}); But now we have two syntaxes that do *almost* the same thing, but with subtle differences, and the existing positional syntax, which means there's now 3 ways to create an object that look very similar visually but mean slightly different things. That's... not good. I still hold that initializers as described, even though I like the problem they're solving being solved, are a strict subset of the combination of named parameters and auto-constructor promotion. If we had those, we would have more functionality and initializer functionality comes for free, and it would be more self-evident what was going on, with fewer syntax variations. Whereas adding initializers now as a one-off would likely make adding those later more difficult. Thus I would rather see time spent on adding those than on a one-off syntax. (And yes, I fully realize I am saying that as someone not currently working on any of the above syntaxes and so I'm talking about other people doing work, etc.) --Larry Garfield