Re: Features related to Object Initializers

This is only part of a thread. view whole thread
September 16, 2019 10:22 (Rowan Tommins)
On Mon, 16 Sep 2019 at 04:13, Mike Schinkel <> 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]