Hi Rowan,
> On May 5, 2020, at 16:47, Rowan Tommins <[email protected]> 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