Features related to Object Initializers

  107133
September 16, 2019 03:13 mike@newclarity.net (Mike Schinkel)
> On Sep 14, 2019, at 4:47 PM, Rowan Tommins collins@gmail.com> wrote: > I think that's only true because you've actually proposed a number of related but different features.
See my other email to the list asking about what is in-bounds and what it out-of-bounds regarding RFC discussion. I seemed logical to me to discuss how to improve an RFC, but maybe what you are saying is that we are only suppose to discuss RFC as it exists today in order to give a black and white, up or down vote on the entire RFC? That seems counter-productive, but if that is the case and others concur then so be it. So to be safe, I have started a new thread for this reply.
> other than initializing additional objects. And if these are additional objects, then named parameters work just as well in the nested case as in the non-nested one: > > $car = new Car( > yearOfProduction => 1975, > vin => "12345678", > engine => new Engine( > type => "v8", > capacity => "270ci", > ), > );
Obviously that can be done. However, in practice I often see arrays used instead of objects because it is so much easier. I doubt that this enhancement will remove the other reasons developers might continue to use arrays instead: 1. Arrays do not require a developer to name a class, where naming is one of the 2 or 3 hardest parts of computer science 2. Anonymous classes are more tedious than just creating an array literal so I see most PHP developers using arrays instead. 3. Defining a class in PHP best practice means creating another file that is physically separate from the code for said class that must also be (auto-)loaded. So are you arguing that in all cases where people want structured information they should create a new class, and if so, what about the three points I just made?
> This already works: > > $stats = new class { > var int $total = 0; > var int $mean = 0; > var int $average = 0; > var int $median = 0; > }; > > What doesn't currently work is using variables from lexical scope in the definition: > > $stats = new class { > var int $total = $a + $b; > var int $mean = $c; > var int $average = $d; > var int $median = $e; > };
In the USA we have a saying: "Besides that Mrs. Lincoln, how was the play?" But for those unfamiliar with US history leading up to the revolutionary war, what it means in this context is: "Yes your point is correct, but ignores the most relevant concern."
> However, initializer syntax on its own doesn't solve this, because you wouldn't be able to specify the types for the properties; just combining existing syntax with initializers would give something like this: > > $stats = new class { > var int $total; > var int $mean; > var int $average; > var int $median; > }{ > total => $a + $a, > mean => $c, > average => $d, > median => $e > }
You probably missed that I wrote that I was using an alternate initialization syntax that I would propose instead, which I will illustrate again below. If we allow typing i $stats = new class { int $total = $a + $b; int $mean = $c; int $average = $d; int $median = $e; };
> You could certainly make the syntax of initializers and anonymous class definitions similar, but they're not really the same thing.
Noted. To me them being the same or not is not as concerning as the outcome of the features that may become available in userland.
> The QueryBuilder class in this example has not benefited from object initializers at all; passing the Query object rather than separate parameters is a refactoring you can (and probably should) do right now.
But many PHP developers are unlikely to do that refactoring initially. They will just fall back to using arrays, because they are easy, comfortable, less pedantic and less tedious to use. I would far prefer to have find developers using untyped anonymous objects than arrays because the former is much easier to refactor to better code than the latter, and this is painfully obvious to me because of numerous PHP codebases I have been brought in to fix. Would it be better to introduce a simple-to-use object instantiation syntax so userland PHP developers would start using it, or would it be better to leave them only one easy option such that they continue to use arrays?
> As before, the definition of the class itself is simpler, but I think a short-hand syntax for constructors would be a better compromise than a syntax that only worked with public properties and parameterless constructors.
My problem with short-hand syntax for constructors is they only work in context of constructors. What about other functions or methods that userland PHP developers currently pass structured arrays too?
> This is an interesting additional proposal, which I admit would be awkward to implement without initializer syntax. One limitation is that it only works if dependencies are declared as concrete classes not interfaces
True. If a function is defined to accept an interface then the caller would be required to pass in an instance of a class that satisfies the interface.
> which like public properties is not "wrong" per se, but limits the scope of the feature.
If we had to have every feature work for everything, we'd never have `foreach,` for example. My belief is that not every feature needs to apply in all contexts in order to be highly useful. Do you believe otherwise?
> Named parameters are (or would be) a way of setting a bunch of variables; they're not linked as an object of any sort, so I don't think there's a natural comparison to anonymous classes at all.
I did not say they _were_ linked, I asked why couldn't/shouldn't they be linked? They are both a group of named "properties" with associated values. Why are they all not equivalent to an object? And why not allow all of them to be treated as an object? Even if there are represented different internally, I see no reason why they could not be made equivalent in userland code. Do you?
> If I understand it right, the next example relies on the combination of anonymous class initialisers, named class initialisers, and named parameters all using the same syntax,
No, I would say that is not what I am proposing. What I am proposing is that one syntax and one set of functionality be used to address all three use-cases rather than have three different functionalities with three different syntaxes, because they seem to be to be all equivalent: 1. anonymous class initialisers, 2. named class initialisers, and 3. named parameters As Larry Garfield said, we are running out of sigils; making one syntax address multiple use-cases seems to me like the most responsible thing to do.
> The examples look really neat on their own, but imagine coming on that syntax in someone else's code and trying to work out what it was doing.
If I see someFunction({bar => 1, baz => 2}) that tells me that someFunction expects bar and bar as integers. When calling functions we are not supposed to know how they are implemented, so why should it matter to the caller whether internally they are captured to individual parameters or into a single parameter array? And when inside the function, why does it matter how they are passed? The reason I proposed this is I would really prefer to come on to this syntax in other's code rather than coming onto the prevailing type of code I see in userland instead; arrays upon arrays. What is not clear to me is why you see it to be confusing?
> There's definitely some interesting ideas here, but they're not all part of one feature,
Can you clarify what you are implying? That I should start other threads to discuss? That I should create new RFCs?
> and they all rely on particular ways of structuring your code.
Is that problematic? Most language features require code to be structured a particular way. I am assuming that PHP is not an opinionated language that defines one way to structure code and shuns all other ways, except for those ways that have been explicitly deprecated by RFC such as magic quotes. Am I incorrect about this? -Mike
  107138
September 16, 2019 07:00 rowan.collins@gmail.com (Rowan Tommins)
On 16 September 2019 04:13:24 BST, Mike Schinkel <mike@newclarity.net> wrote:
> >> On Sep 14, 2019, at 4:47 PM, Rowan Tommins collins@gmail.com> >wrote: >> I think that's only true because you've actually proposed a number of >related but different features. > > >See my other email to the list asking about what is in-bounds and what >it out-of-bounds regarding RFC discussion. > >I seemed logical to me to discuss how to improve an RFC, but maybe what >you are saying is that we are only suppose to discuss RFC as it exists >today in order to give a black and white, up or down vote on the entire >RFC? That seems counter-productive, but if that is the case and others >concur then so be it.
I'll try to reply in detail later, but to clarify, I was not saying that your message was off topic. What I was saying was that what you described as one feature with lots of applications seems to me like lots of features with overlapping syntax. There's nothing wrong with that, but it means that we don't get some of the stated benefits unless/until all the features are implemented, and I think it's useful to break down what each feature gives on its own. Regards, -- Rowan Tommins [IMSoP]
  107162
September 16, 2019 10:22 rowan.collins@gmail.com (Rowan Tommins)
On Mon, 16 Sep 2019 at 04:13, Mike Schinkel <mike@newclarity.net> wrote:

> > Obviously that can be done. However, in practice I often see arrays used > instead of objects because it is so much easier. I doubt that this > enhancement will remove the other reasons developers might continue to use > arrays instead: > > 1. Arrays do not require a developer to name a class, where naming is one > of the 2 or 3 hardest parts of computer science > > > 2. Anonymous classes are more tedious than just creating an array literal > so I see most PHP developers using arrays instead. > > > 3. Defining a class in PHP best practice means creating another file that > is physically separate from the code for said class that must also be > (auto-)loaded. > > > So are you arguing that in all cases where people want structured > information they should create a new class, and if so, what about the three > points I just made? > >
Points 1 and 3 are solved by anonymous classes, which we already have. Point 2 is a bit vague; is your point essentially "if we had nicer syntax for anonymous classes people would use them more"? If so, then see next section; if not, I'd like more clarification on what you were trying to illustrate with your "nested parameters" example.
> If we allow typing i > > $stats = new class { > > int $total = $a + $b; > > int $mean = $c; > > int $average = $d; > > int $median = $e; > > }; > > > > You could certainly make the syntax of initializers and anonymous class > definitions similar, but they're not really the same thing. > > > Noted. To me them being the same or not is not as concerning as the > outcome of the features that may become available in userland. > >
The problem with trying to make anonymous class declarations and object initalizers look and feel similar is that there's a lot more that can go into an anonymous class declaration: types, visibility, methods, traits, "extends" and "implements" clauses, etc. I think that's a good reason not to think of them as related features, unless you can think of use cases where having variable capturing in an anonymous class declaration would mean you would no longer want object initializers?
> > The QueryBuilder class in this example has not benefited from object > initializers at all; passing the Query object rather than separate > parameters is a refactoring you can (and probably should) do right now. > > > But many PHP developers are unlikely to do that refactoring initially. > They will just fall back to using arrays, because they are easy, > comfortable, less pedantic and less tedious to use. > > I would far prefer to have find developers using untyped anonymous objects > than arrays because the former is much easier to refactor to better code > than the latter, and this is painfully obvious to me because of numerous > PHP codebases I have been brought in to fix. > > Would it be better to introduce a simple-to-use object instantiation > syntax so userland PHP developers would start using it, or would it be > better to leave them only one easy option such that they continue to use > arrays? > >
I'm a bit confused here whether we're talking about constructing objects of anonymous classes, named classes, or both. Your example showed constructing a defined Query object, but your comments above sound more like they're about using anonymous classes (as a replacement for arrays). Either way, I agree with the aim of making objects easier to construct, I'm just discussing the pros and cons of the various suggestions for doing that.
> As before, the definition of the class itself is simpler, but I think a > short-hand syntax for constructors would be a better compromise than a > syntax that only worked with public properties and parameterless > constructors. > > > My problem with short-hand syntax for constructors is they only work in > context of constructors. > > What about other functions or methods that userland PHP developers > currently pass structured arrays too? > >
I don't understand what you mean here. Your example showed a QueryBuilder class being refactored to use a Query object instead of multiple parameters, which is something that can happen right now, no language changes needed. The only new feature your example showed was a different way of constructing the Query class.
> which like public properties is not "wrong" per se, but limits the scope > of the feature. > > > If we had to have every feature work for everything, we'd never have > `foreach,` for example. > > My belief is that not every feature needs to apply in all contexts in > order to be highly useful. Do you believe otherwise? > >
I agree, and I never said otherwise. I do think that an important part of deciding whether to implement a feature is evaluating its limitations, and what use cases it would and wouldn't help with. I'm not saying this feature should never happen because it doesn't work with interfaces, I'm just saying that is a limitation to consider. Named parameters are (or would be) a way of setting a bunch of variables;
> they're not linked as an object of any sort, so I don't think there's a > natural comparison to anonymous classes at all. > > > I did not say they _were_ linked, I asked why couldn't/shouldn't they be > linked? > > They are both a group of named "properties" with associated values. Why > are they all not equivalent to an object? > And why not allow all of them to be treated as an object? > >
I don't particularly see them as a "group". If I write foo($a, 42), I don't think of $a and 42 being bound together in any way; each is passed as a value to one variable in the function. So that's my answer to "why not"; they just don't feel like related ideas to me. If I understand it right, the next example relies on the combination of
> anonymous class initialisers, named class initialisers, and named > parameters all using the same syntax, > > > No, I would say that is not what I am proposing. What I am proposing is > that one syntax and one set of functionality be used to address all three > use-cases rather than have three different functionalities with three > different syntaxes, because they seem to be to be all equivalent: > > 1. anonymous class initialisers, > > 2. named class initialisers, and > > 3. named parameters > >
Even if they use the same syntax, those are not the same piece of functionality, or equivalent. The first two are certainly related, but the last one I just don't see the connection.
> > The examples look really neat on their own, but imagine coming on that > syntax in someone else's code and trying to work out what it was doing. > > > If I see someFunction({bar => 1, baz => 2}) that tells me that > someFunction expects bar and bar as integers. When calling functions we are > not supposed to know how they are implemented, so why should it matter to > the caller whether internally they are captured to individual parameters or > into a single parameter array? And when inside the function, why does it > matter how they are passed? > > The reason I proposed this is I would really *prefer *to come on to this > syntax in other's code rather than coming onto the prevailing type of code > I see in userland instead; arrays upon arrays. > >
This feels like a straw man to me: "if we don't unify named parameters with object initializers, everyone will use arrays". I would definitely be happy seeing objects being passed around more; but this syntax isn't the only way to encourage that, and I think its costs outweigh its gains.
> What is not clear to me is why you see it to be confusing? > >
Consider this code: class Customer { public string $name; public ?int $age=null; } function doSomething(?Customer $customer=null, ?string $name=null) { // ... } doSomething({name => 'John Smith'}); Is this equivalent to: doSomething(new Customer{name='John Smith'}, null); or: doSomething(null, 'John Smith'); If I change the public properties of the Customer class, does that change the result? If the parameter was mandatory, would that be different? If it wasn't type-hinted, would I get an anonymous object? It's all too ambiguous and context-dependent. Compare that to separate syntax for the separate features: doSomething(new class extends Customer { string $name='John Smith'; }); doSomething(new Customer{ name='John Smith' }); doSomething(name => 'John Smith'); All are nice and short, but there's no ambiguity; I don't need to read the rest of the code to understand what each line is doing.
> > There's definitely some interesting ideas here, but they're not all part > of one feature, > > > Can you clarify what you are implying? That I should start other threads > to discuss? That I should create new RFCs? > >
I wasn't really implying anything beyond what I said: there's lots of different ideas in here, but I wouldn't expect them all to be listed as one feature in, say, a user manual.
> > and they all rely on particular ways of structuring your code. > > > Is that problematic? Most language features require code to be structured > a particular way. > > I am assuming that PHP is not an opinionated language that defines one way > to structure code and shuns all other ways, except for those ways that have > been explicitly deprecated by RFC such as magic quotes. Am I incorrect > about this? > >
I didn't say it was "problematic"; again, I'm just trying to evaluate these ideas, and part of that is working out their limitations, and whether there are alternatives that can be used in more scenarios. Regards, -- Rowan Tommins [IMSoP]