Hey Theodore, <http://ocramius.github.com/>
On Tue, May 5, 2020 at 6:59 PM Theodore Brown <theodor...@outlook.com> wrote: > On Tue, May 5, 2020 at 9:11 AM Marco Pivetta <ocram...@gmail.com> wrote: > > > As mentioned some days ago, I see named parameters as an added liability, > > rather than values. > > The rationale of my negativity around the topic being that a diff like > > following is now to be considered a BC break: > > > > ```diff > > -function foo($parameterName) { /* ... */ } > > +function foo($newParameterName) { /* ... */ } > > ``` > > If the function is part of your own codebase, BC Breaks that are intra-codebase are rarely every a problem nor a point of discussion. > an IDE can automatically > update function calls when renaming a parameter. For functions that are > part of a public API, yes, parameters shouldn't be renamed outside of > major versions. But in my experience, it's rare for function parameters > that are part of public APIs to be renamed. Do you have many real-world > examples of where this had to happen? > Parameter name changes are very much normal, since (as I already posted in /r/php), naming is hard, and getting it right is not a one-shot effort. Also, I haven't heard of this being a big problem in other languages > with named arguments like Python. > Good question: I guess parameter renames are avoided on purpose? Not familiar with the python community myself, sorry. Why do you say that? For me this feature would be extremely helpful > when calling constructors that have several optional arguments (e.g. > similar to the `ParamNode` example in the RFC). Maybe you consider > this a bad API, I do in fact consider the `ParamNode` example in that API to be a bad candidate for named parameters, since I'd make all of the arguments in that signature required anyway: defaults aren't meaningful anyway, as the AST library where it comes from has all the context to instantiate them all (the caller, being the parser, will have all the parameters anyway). If you were to instantiate a `ParamNode` from, for example, a `ReflectionParameter`, you would probably add named ctor (or an indepentent factory, if in external supporting domain) to pass all parameters as well. If you were to add more optional fields, or use this in a context of an AST builder (BTW, nikic/php-parser has facilities for that already) a mutator would be efficient too: ```php class ParamNode extends Node { public function asReference(): static { $instance = clone $this; $instance->byRef = true; return $instance; } ``` but it's a very common pattern, and named arguments > will make it far easier to work with than the typical alternative of > converting arguments to an options array (which is itself a BC break > and has many other downsides as the RFC points out). > You can add as many named constructors as you want: adding `ParamNode::fromArray()` is possible. > > In practice, the issues around bad API (in this case, bad = lots of > > optional parameters, maybe even ordered arbitrarily) are fixed by > > using proper value types and structs or value objects > > How can lots of optional parameters be "fixed" in practice with structs? > E.g. how would they improve the `ParamNode` example in the RFC? Would > it even be possible to migrate existing classes like this to structs > without a BC break? > It is possible to add more named constructors in a BC compliant way, while it is hard to change existing public constructors: * `::fromArray()` * `::fromReflectionProperty()` * `::make(string $name, ?ExprNode $default, ?TypeNode $type, bool $byRef, bool $variadic)` * `::makeForPHP53(string $name, ?ExprNode $default, ?TypeNode $type, bool $byRef)` - no variadic support? No problem :-) * `::makeWithCodeLocation(string $name, ?ExprNode $default, ?TypeNode $type, bool $byRef, bool $variadic, CodeCoordinates $coordinates)` All of the above are possible BC-friendly growth directions for such kind of data structure. They also provide better type definitions, context, naming and invariants than a single signature that has to cover all use-cases at once. Personally I think it's a lot simpler and more consistent to have named > arguments which can be used anywhere, including in attributes, vs. > having to implement and learn a new syntax for structs which only works > for that one use case (and may not be easy to migrate to). > No new syntax: we already have the tools. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/