Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:110018 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 3704 invoked from network); 5 May 2020 19:47:18 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 5 May 2020 19:47:18 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id AB719180503 for ; Tue, 5 May 2020 11:22:17 -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=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-lf1-f44.google.com (mail-lf1-f44.google.com [209.85.167.44]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 5 May 2020 11:22:16 -0700 (PDT) Received: by mail-lf1-f44.google.com with SMTP id s9so2189561lfp.1 for ; Tue, 05 May 2020 11:22:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=meLSBwY1GhCNkDA61fX2g2uhQEplBZcaRQXADzmtSjI=; b=lNqKnlskvbSZexf0cu+mtc1XrB/DbJr40gR6eT2pc9EpcxsV4BUgj+gR+JnU9JhM9Q LJlK1BSXTrsTJu+dI3CbTl981X6xaydtMZnoxrh9IJZHzjMlAC1Niqgu3RiXx+vqtn6M 9o/jZaL/pCMFC5WQAiWllXB2ze0GLAp0BNJlZTO3aVSsybxo5y7Vmo5X7DwYLFbh9B+h JesfbQhpOKshwrkchBE2MCM3H7eycXR8kph1VdOtRsobUt9N+oIS5iZtwu+KHOHSY2OO /qH+oVegMkfX6Ums02cdUy05VdkbB0G1je0lTmXLp36m+JmxSQmE1+AOr+BctaWt/wbE NCsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=meLSBwY1GhCNkDA61fX2g2uhQEplBZcaRQXADzmtSjI=; b=MB1S9mX3Lq2LnBV85VWmEbUBol851R2VOhUcHK2kNNEE52uEuvVet9FO3AKkU9zOpR t0JiOYEG9PvnVGvIH1fs5T3f6VI1kqRxF7O8BMWswxPDSSo8K9rLVH2xvw5KaVvM+MCo RI2+xrM6nCrmjyV/VMaTDdk0ojZkFcYSYRH3rOXdKRRyUXfJa93Gder3BsZf/fYmhkef 9NF0x/rnAl9pjeiwun4+QAtmt24muv5pHMk1p1yYaRQpJDz1NtPegdQvVRyI6TzIhHSb il4MypOPpoH8vgIIIZV59F4rhg68QLYyPV7L1KFEsyqKYqhbp1e4rDhD4VgP7xqOko2k c1CA== X-Gm-Message-State: AGi0PuahaQ6A80HBHNDvDYA5kLRGvoYwKRtue5TyAbp5ryALN1Ei5Izc dSyBnL0PY9AWKy/KAVydYASR1aP7AlqCqNbOMB8= X-Google-Smtp-Source: APiQypINJ/FRdiDqGaK07TYQvewAorf1Fudg3jw+qFqOdiVEOY190Xg96dOqa32Ul8hmYjQaz0ydRGrU6c9Fw/QJ1Nk= X-Received: by 2002:a05:6512:44e:: with SMTP id y14mr2474977lfk.190.1588702934704; Tue, 05 May 2020 11:22:14 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Tue, 5 May 2020 20:21:58 +0200 Message-ID: To: Marco Pivetta Cc: Theodore Brown , PHP internals Content-Type: multipart/alternative; boundary="00000000000013a81805a4eaba97" Subject: Re: [PHP-DEV] [RFC] Named arguments From: nikita.ppv@gmail.com (Nikita Popov) --00000000000013a81805a4eaba97 Content-Type: text/plain; charset="UTF-8" On Tue, May 5, 2020 at 7:19 PM Marco Pivetta wrote: > Hey Theodore, > > > > On Tue, May 5, 2020 at 6:59 PM Theodore Brown > wrote: > >> On Tue, May 5, 2020 at 9:11 AM Marco Pivetta 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; > } > ``` > Reminds me of the saying: Design patterns are just standardized workarounds for language limitations. Builders and withers? Those are not, intrinsically, good code. They are workarounds for lack of good object initialization support. I should not have to implement a large amount of builder boilerplate to make the construction of simple objects safe and ergonomic. We're not talking about some kind of complex multi-stage construction logic here, but the construction of what essentially amounts to a value object. Generally, named arguments really change what constitutes a good API and what doesn't. Things like boolean flags to functions are considered bad design *because* we do not have named arguments. If I pick out some random Python API, say subprocess.run()... subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None) ... and show that to a PHP developer, they're probably going to tell me that this is horrible API design. They would, of course, be wrong. It's reasonable API design, just in a language that supports named arguments. Anyway. Your point that named arguments expand the API surface has been acknowledged. I don't think this issue is really avoidable, it's a rather fundamental trade-off of named parameters. I do think you're a bit quick in jumping to conclusions. It's not like this problem doesn't exist in (nearly) every language supporting named arguments. There are some things we can do to mitigate this though. One that we recently discussed in chat is to allow methods to change parameters during inheritance, and allow named arguments to refer to the parameter names of the parent method as well. Renaming parameters in a way that causes conflicts (same parameter name at different position) would cause an LSP error. I'm not entirely convinced this is the best approach yet, but this does address some concerns (including the "interface extraction" concern you mention on reddit). Another is to allow specifying the public parameter name and the private parameter variable name separately, as is possible in Swift. This would allow changing "parameter" names arbitrarily, without breaking the public API. This would be a pretty direct counter to your concern, but I'm not really sure that your concern is important enough to warrant the additional weight in language complexity. I've never used Swift myself, so maybe this is actually awesome and I just don't know it. Regards, Nikita --00000000000013a81805a4eaba97--