Hi Rowan, > On May 5, 2020, at 16:47, Rowan Tommins <rowan.coll...@gmail.com> wrote: > > Hi John, > > On 05/05/2020 18:27, John Bafford wrote: >> I very much do like the idea of named parameters, but I do not like the >> specific proposal in the linked RFC at all. I think that treating named >> parameters simply as syntactic sugar is not a good approach. If we're going >> to add named parameters, I think they should actually be significant in >> their own right. As such, please allow me to present an alternative. >> >> I would propose the following opt-in mechanism, which would work by treating >> the parameter names as*part of the function name*. Doing it this way >> I_think_ should allow for no backwards compatibility issues with existing >> code and would especially give library authors full control over the naming >> and presentation of their APIs. > > > I really like *some* of this proposal, but I think some of it is solving a > different problem. > > > You mention in a later e-mail that you've been heavily inspired by Swift; > Swift in turn was inspired by Objective C, which was inspired by Smalltalk. > This is an important piece of history, because Smalltalk doesn't actually > have methods with named parameters; it has "keyword messages" whose > "selectors" are things like "indexOf:startingAt:". Swift makes them look more > familiar by keeping part of the name separate from what it calls "argument > labels", so a method might be called "indexOf(_:startingAt:)" or > "index(of:startingAt:)".
You're not wrong here, but, I think that's an (critical) implementation detail of Objective-C and Smalltalk that is not relevant here. Also, Swift does not use selectors or message passing, unless either interoperating with ObjC classes, or the code has explicitly opted-in. Normally, Swift function/method calls are statically determined at compile time in a way similar to C/C++. > Although at a glance these look like named parameters, and they solve some of > the same problems, they're actually a fundamentally different concept. > > They have some nice features: > > * Method calls can be made to read like sentences > * The external API of the function is kept separate from the internal > implementation > * You can skip over default arguments by omitting their labels > * Overloading what looks like one method, by having different methods whose > names start the same but have different "argument labels", may be appealing > > But there are some crucial limitations: I don't think any of your points are downsides to the proposal. A lot of these I think boil down to the conflict between, "as an API user, I should be able to do whatever I want", and, "as an API author, I have decided my API will be used like this". I generally side with the API author being specific on how their API will be used. > * You can't call a method without using its labels; you'd need to have a > separate method with a similar name and no labels If a function/method has labels, you're required to use them. Otherwise, you can't get the benefit of using them for name-based "overloading". For example, if you have the methods function firstIndex(of: $element) : ?int function firstIndex(where: callable $predicate) : ?int You can't just call $collection->firstIndex($foo), because the compiler would have no idea which method it refers to. And while you _could_ have a function firstIndex($param) that tries to determine which specific method to call, but now you've turned a compile-time static call into a runtime check, and that might still not be sufficient, for example, if you have a collection of callables! The labels are part of the method's name, which happen to be written inside the parenthesis. I just argue that both of those are more readable than either of these: function firstIndexOfElement($elt) : ?int function firstIndexMatchingPredicate(callable $predicate) : ?int If I give my method a particular name, I expect users to call them as such. If the user doesn't like it, then they can wrap the class and provide their own alternate interface. > * Similarly, it's up to the method's author to have versions with a mixture > of unlabelled and labelled parameters, so a call like "create('hello', 42, > locked: true)" is only possible if that specific variant is defined As above: a method's author is under no compulsion to do so. If I define my API to be create('hello', fontSize: 42, locked: true), then that's how I expect my users to call it. > * You can't use the labels in the "wrong" order, you have to know the order > they come in; so it doesn't solve the haystack/needle problem, except by > creating extra function definitions I don't think this is a problem either. In some cases, the extra context by having the parameter names spell out a gramatically-correct sentence structure will help with memorizing the order. In other cases, the constant repetition will help. If you visually see strpos(haystack: $str, needle: $str) all over the place, it will help; but this can also be used as a way to fix the problem by completely sidestepping it, by adding new functions/methods that offer more clarity: strpos($string, in: $haystack); position(of: $string, in: $haystack) indexOf($str, in: $haystack) In those examples, the sentence-like structure of the call, which are all variations on, "what is the position of $string in $haystack?" makes it more memorable. > * Similarly, methods with large numbers of arguments are still hard to use > because you need to know both the name *and* the relative position of the > arguments you're providing (imagine defining variants with every order of the > 5 bit flags in the AMQP example in my earlier e-mail) Well, you wouldn't define variants for each order, you'd just rely on the compiler (or IDE) to help the user. So if I tried to call $channel->queue_declare('name', arguments: $args, durable: true) I'd expect the compiler to report back something along the lines of, "parameters are in the wrong order; use queue_declare(_: passive: durable: exclusive: autodelete: nowait: arguments: ticket:)". Maybe even prefix or postfix the parameter names with a ? to indicate the ones that are optional because there's a default value. Yes, you _could_ add additional function definitions to handle whatever random order people want to use functions in, but you don't have to, and most API authors probably wouldn't. Because there's generally only a few "correct" ways to word most sentences. In that regard, AMQP::queue_declare is a pathological exception. There may be a good reason for its specific order, but lacking that knowledge, it appears to be completely arbitrary and nonintuitive. If I said to someone, "language the hard improve working We constantly PHP to are", they'd probably look at me funny. We don't accept people speaking human language with randomized word order; neither should API authors (or other developers) be expected to accept people using APIs with randomized parameter orders. > It would be possible to take the "outside name is different from inside name" > concept and apply it to named parameters proper. But the problems I would > like to solve with named parameters wouldn't be solved by Swift/Smalltalk > style functions. > > > Regards, > > -- > Rowan Tommins (né Collins) > [IMSoP] -John -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php