Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:110048 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 85966 invoked from network); 6 May 2020 19:43:29 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 6 May 2020 19:43:29 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id C9E091804CB for ; Wed, 6 May 2020 11:18:42 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RDNS_NONE,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS701 96.241.0.0/16 X-Spam-Virus: No X-Envelope-From: Received: from nebula.zort.net (unknown [96.241.205.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 6 May 2020 11:18:42 -0700 (PDT) Received: from [10.0.1.2] (pulsar.zort.net [96.241.205.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by nebula.zort.net (Postfix) with ESMTPSA id 62B122005E8C7; Wed, 6 May 2020 14:18:41 -0400 (EDT) DKIM-Filter: OpenDKIM Filter v2.11.0 nebula.zort.net 62B122005E8C7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zort.net; s=zort; t=1588789121; bh=DnJaBEXBssjA7nk7maQu2R784TN7gRMv5ZY4Xbo2u1M=; h=Subject:From:In-Reply-To:Date:Cc:References:To:From; b=ZgUQdQliQOtAxnGgXmJjW20JWh/54pHqeV7nZ1Pqk5ohh+jGISxMRy8IHNRjOaGWP nFzPl4yASKYdfpeUgz02/W9KILqPBXWxu7bIXkzRPKsbI+/XCkzvyrfT/LVaQgKFcM +Uk+Bod+FE9I2xBauwyzh5vo35d56LDb0BN+v0EE= Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.80.23.2.2\)) In-Reply-To: <439e7c43-8d17-1398-d72e-c7ae6942ce86@gmail.com> Date: Wed, 6 May 2020 14:18:41 -0400 Cc: internals@lists.php.net Content-Transfer-Encoding: quoted-printable Message-ID: <8A17FF2D-9CD4-4DF2-B352-7079FCC7F104@zort.net> References: <439e7c43-8d17-1398-d72e-c7ae6942ce86@gmail.com> To: Rowan Tommins X-Mailer: Apple Mail (2.3608.80.23.2.2) Subject: Re: [PHP-DEV] [RFC] Named arguments From: jbafford@zort.net (John Bafford) Hi Rowan, > On May 5, 2020, at 16:47, Rowan Tommins = wrote: >=20 > Hi John, >=20 > 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. >>=20 >> 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. >=20 >=20 > I really like *some* of this proposal, but I think some of it is = solving a different problem. >=20 >=20 > 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. >=20 > They have some nice features: >=20 > * 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 >=20 > 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. >=20 >=20 > Regards, >=20 > --=20 > Rowan Tommins (n=C3=A9 Collins) > [IMSoP] -John=