Re: [PHP-DEV] [RFC] [DISCUSSION] Compact Object Property Assignment

This is only part of a thread. view whole thread
  109063
March 16, 2020 15:40 rowan.collins@gmail.com (Rowan Tommins)
On Mon, 16 Mar 2020 at 11:48, Jakob Givoni <jakob@givoni.dk> wrote:

> https://wiki.php.net/rfc/compact-object-property-assignment > - A pragmatic approach to object literals > > Let me know what you think! >
Hi Jakob, Thanks for having another go at this feature, which I think a lot of people would like in some form. I think I agree with Matthew that the almost-but-not-quite array syntax looks a bit odd, but that's something that can be worked on if we agree the basic idea is sound. I fear that the need to directly set public properties (or use __set) would limit the use cases of this somewhat. I can see two ways we could arrive at something more broadly useful: * A syntax like this, plus better support for property setters (inline like in C# etc, rather than needing __set) * Named parameters plus short-hand constructor definitions (e.g. function __construct($this->foo) removing the need to type $this->foo = $foo) Maybe we want to have all four, but that would leave us with a lot of different ways of initialising objects, which might not be such a good thing. You mention using "argument bag" objects in place of named parameters, but that feels like it would be even more awkward than using an associative array. To get the example in the RFC doing something useful, you'd need quite a lot of boilerplate: class FooOptions { string $mane; string $hum; } class Foo { string $mane; string $hum; public function __construct(FooOptions $options) { // Still have to check for uninitialized properties, since COPA won't enforce them if ( ! isset($options->mane) || ! isset($options->hum) ) { throw new Exception('Bad options'); } // Still have to copy parameters one at a time $this->mane = $options->mane; $this-> hum = $options->hum; } } $myFoo = new Foo((new FooOptions())->[ mane = 'get', hum = 'life', ]); Compare that to named parameters (picking a syntax that looks similar to yours), even without any new constructor syntax: class Foo { string $mane; string $hum; public function __construct(string $mane, string $hum) { // Type and mandatory param checks are automatic // Still have to copy parameters one at a time, unless we $this->mane = $mane; $this-> hum = $hum; } } $myFoo = new Foo([ mane = 'get', hum = 'life', ]); Writing that out also made me realise a key difference between this and constructor short-hands, which is that COPA can only validate individual parameters, not the whole object; so it's hard to complain if the user forgets a mandatory field. Sometimes that wouldn't matter, but again, it limits the cases where this syntax would be useful, even if we had property setters. Regards, -- Rowan Tommins [IMSoP]
  109089
March 17, 2020 01:47 jakob@givoni.dk (Jakob Givoni)
On Mon, Mar 16, 2020 at 10:40 AM Rowan Tommins collins@gmail.com> wrote:
> Thanks for having another go at this feature, which I think a lot of people > would like in some form. I agree!
> Maybe we want to have all four, but that would leave us with a lot of > different ways of initialising objects, which might not be such a good > thing. Remember that the RFC explicitly says it's not an object initializer,
nor does it solve "named parameters" which you mention. If I had the choice, I'd go with named parameters when creating an object, but I don't and this is the next best thing. It's simple and it doesn't introduce any new concepts. It just allows you to do something inline that you could until now only do line by line.
> You mention using "argument bag" objects in place of named parameters, but > that feels like it would be even more awkward than using an associative > array. The associative array is a common pattern, but it defeats name and
type checking. An Options class add almost no extra boilerplate since you simply move the properties from the main class to the Options class. Notice that in contrary to your example, I simply copy the Options object whole into the main class.
> COPA can only validate individual > parameters, not the whole object; so it's hard to complain if the user > forgets a mandatory field Correct, the goals for COPA are quite clear in the "Motivation"
section and that kind of validation is not one of them Luckily you can still do things the way you prefer without COPA if it doesn't suit you :-) Best, Jakob
  109105
March 17, 2020 14:30 rowan.collins@gmail.com (Rowan Tommins)
On Tue, 17 Mar 2020 at 01:47, Jakob Givoni <jakob@givoni.dk> wrote:

> Remember that the RFC explicitly says it's not an object initializer, > nor does it solve "named parameters" which you mention. >
I wasn't expecting COPA to "solve" named parameters, just thinking that if we already had named parameters, we might not bother with COPA. That said, your "argument bag" example looks very much like it's trying to solve named parameters to me.
> An Options class add almost no extra boilerplate since you simply move > the properties from > the main class to the Options class. > Notice that in contrary to your example, I simply copy the Options > object whole into the main class. >
Hm, I see, that does reduce the boilerplate somewhat, although it's still split across two classes, and probably therefore two files, which is not great. You're missing some code in your example, though, because you've documented one of the options as optional, implying the others should be mandatory; in which case you need something like this in the constructor: if ( ! isset($options->mane) || ! isset($options->hum) ) { throw new Exception('Bad options'); } Which would soon get longer with more complex options. Maybe it would be refactored out into $options->isValid() or something, but it would have to go somewhere, or you'll just get "uninitialized property" errors in random parts of your application. You'd also want to copy the property onto the real object if it was initialising state rather than retaining a constant value; it would be a bit weird to write $this->options->counter++ instead of $this->counter++
> > > COPA can only validate individual > > parameters, not the whole object; so it's hard to complain if the user > > forgets a mandatory field > Correct, the goals for COPA are quite clear in the "Motivation" > section and that kind of validation > is not one of them > Luckily you can still do things the way you prefer without COPA if it > doesn't suit you :-) >
It's not so much about preferring different styles, it's about what circumstances this will be useful. It seems pretty rare that an object would have no mandatory properties, so saying "if you have a mandatory property, COPA is not for you" is ruling out a lot of uses. It might be interesting to have the syntax run before the constructor rather than after, or trigger some other magic method which could do tidying and validation, so it could apply to more circumstances. Regards, -- Rowan Tommins [IMSoP]
  109120
March 18, 2020 02:57 jakob@givoni.dk (Jakob Givoni)
On Tue, Mar 17, 2020 at 9:31 AM Rowan Tommins collins@gmail.com> wrote:
> Hm, I see, that does reduce the boilerplate somewhat, although it's still > split across two classes, and probably therefore two files, which is not > great. As an alternative to passive associative arrays, it's a small price to pay for
splitting concerns and having a documented signature for the data structure. Named parameters is another alternative (unfortunately outside reach for now) that would work great for a limited number of arguments. COPA does not make named parameters obsolete, but works great for any number of arguments.
> You're missing some code in your example, though, because you've documented > one of the options as optional, implying the others should be mandatory; in > which case you need something like this in the constructor: I've rewritten parts of the RFC and some examples substantially,
and added your view of mandatory arguments in the "Open Issues" section.
> It might be interesting to have the syntax run before the constructor > rather than after, or trigger some other magic method which could do > tidying and validation, so it could apply to more circumstances. Hmmm, in the Write Once Properties RFC they seem to believe
that object construction is a "fuzzy" term and that lazy initialization is a feature. We can add better 'automagic' support for mandatory arguments, filtering and validation in incremental proposals, to avoid biting off more than we can chew, but we have to start somewhere.