I'm ambivalent.

There's a tension in PHP-land between PHP's roots as a low-ish level, get-it-done, hackish language, with its big standard library and simple scalar types, and the better-organized and quite vocal developers who want it to be more Java-like, with great big frameworks and many deeply-nested complex class hierarchies. Instead of unwieldy hobbyist-hacker balls of mud, you build enterprise-scale balls of mud.

Named arguments don't do a lot for the first group. It looks like the big point in favor is not having to look up a reference for which-arguments-go-where in functions anymore, but a good IDE already does that for you.

But there is a common anti-pattern where you have some polymorphic function or interface, and you want to accrete your arguments somewhere and then bundle them up and call the function, so then you see things like [1]:

    call_user_func($function, ['length' => $n, 'foo' => $bar, ...]);
...and that is bad because it totally bypasses all of PHP's type-checking and leaves it up to the called function to sanity-check the input types instead of letting the compiler do it, and basically nobody does that anyway.

So named parameters would fix that at least, which would be nice. I'm just not looking forward to the impact this is going to have on code readability, because everyone (including this article) is going to go, "oh, now my parameter list is too long!", and break the function signature into one-line-per-parameter, which is vile.

[1]: I'm guilty of this too.

> break the function signature into one-line-per-parameter, which is vile

Speak for yourself. If each line indicates what it is the parameter for I couldn’t care less.

Nobody will use this for functions that have just two parameters. It’s the ones that have 10 possibilities that are crazy.

Other than plain object constructs these kinds of functions are unheard of and better handled with a parameter object or array.

I can't help but feel if they just set up a clean way to name construct Params for classes this wouldn't need to happen.

Why are they better handled with a parameter object or array? https://news.ycombinator.com/item?id=23962955

What is the functional difference between a named construct "Params" and just allowing named parameters?

> What is the functional difference between a named construct "Params" and just allowing named parameters?

That "just" is doing a lot of work. I've not used PHP for a few years, but off the top of my head I can forsee the following problems:

- `call_user_func` would need to change to support this, e.g. accepting and passing-along named parameters.

- `call_user_func_array` would need to change, e.g. passing along associative-array arguments as named parameters.

- `func_get_args` would need to change, e.g. returning an associative array

Other parts of the standard library, like ReflectionParameter, would also need corresponding changes.

On their own I don't think those are necessarily bad. However, this would break a lot of code which relies on those functions and their invariants. For example, currying and partial application would become more complicated (e.g. http://chriswarbo.net/blog/2014-02-21-partial_application___... ).

I'm not necessarily against this change, but I would make the following points:

Extending APIs is a breaking change, since it breaks invariants/contracts that previously held (in this case by function definitions and call sites). This breaks backwards-compatibility, and that should be acknowledged and stated explicitly, rather than ignored. Here's a quick example of code which breaks, since it relies on the now-violated invariant that the parameter order of a function call matches that of the definition:

    function call_with_strings() {
      $args    = func_get_args();
      $f       = array_shift($args);
      $strings = [];
      foreach ($args as $arg) {
        $strings[] = strval($arg);
      }
      return call_user_func($f, $strings);
    }
Secondly: there's a definite bandwagon effect between scripting languages like PHP/Python/JS/etc., for better (easier to transfer between) or worse (uncompelling monocultures lacking innovation/USP). Just because a feature exists in one, doesn't necessarily make it a good idea for the others (or the first, for that matter!); conversely, there are lots of great features out there which scripting languages don't seem to have picked up, and which are hardly ever brought up in these discussions. For example:

- Default arguments are generally supported, e.g. `parseInt(i, base=10)`. Alternative approaches to the same problem, like currying, are mostly absent, e.g. `parseIntFor(base, i); parseInt = parseIntFor(10);`

- Generators are generally supported, e.g. `for x in foo: yield x`. Alternative approaches to the same problem, like delimited continuations, are mostly absent, e.g. `reset; for x in foo: shift(x);`. This is especially interesting, since it's just an extension of exception handling, which is another generally-supported feature!

- Named parameters are generally supported, e.g. `foo(a=1, c=5)`. Alternative approaches to the same problem, like row-polymorphism, are mostly absent, e.g. `foo(['a' => 1, 'c' => 5])`.

So one of your arguments is that it'll be difficult to maintain the C implementation of call_user_func, call_user_func_array and func_get_args? But this has already been done by the PHP maintainers.

As for your argument that it breaks code that today relies on argument order... Even in current versions of PHP, nothing in the language stops me from changing function f($a) to function f($b, $a) between v1 and v2 of my library and your code is equally broken. Whether I as a function author decide to re-order my arguments is a decision informed but not dictated by the existence of named arguments.

I don't understand your rant about bandwagons/monoculture. If you ask me the reasons most popular langauges are moving in the same direction is because popular languages are stealing each others' best ideas, which is a good thing. All your "alternative" solutions read like horrible code to me compared to the now commonly accepted designs.

> So one of your arguments is that it'll be difficult to maintain the C implementation of call_user_func, call_user_func_array and func_get_args?

No, I wasn't talking about C; or about language implementations at all. I was arguing that the phrase "just allowing named parameters" gives the impression that this feature would only affect function calls and definitions, when that's not the case. The most obvious repercussions are for `call_user_func`, `func_get_args`, etc. whose API would need to change. That induces changes to code that calls those functions, and code that calls that code, and so on.

Although PHP is famously un(der)specified, I'm talking about things like "`call_user_func(f, args...)` is equivalent to `f(args...)`"; anything relying on that property will break in the presence of named parameters (since they may be given in a different order), unless patched to take it into account.

> Whether I as a function author decide to re-order my arguments is a decision informed but not dictated by the existence of named arguments.

Sure, but that's just a first-order effect. It's a breaking change for higher order code (where functions and arguments are data, and calling is an operation on that data). That's why I gave an example of higher-order code.

As a silly analogy: if PHP extended its default numeric types to be complex numbers, that wouldn't affect existing values like `$age = 18` or `$length = 50`, since they're "informed, but not dictated by the existence of complex numbers"; it also wouldn't affect calculations using these values like `plus($age, $length)`. Yet it would have profound effects on numeric functions, which may have to be patched to take complex values into account: some functions, like `array_sum`, might work fine as-is; whilst others, like `array_slice`, might make no sense given the new situation (how might we take `3+5i` elements from an array?).

> All your "alternative" solutions read like horrible code to me compared to the now commonly accepted designs.

This sentence is a good example of what my "rant" is about. Why should improvements depend on what's "commonly accepted" (surely that's antithetical)? Could you elaborate any further on what makes those examples "read like horrible code"?

As a more detailed example we can look at `switch`: it's clearly a "now commonly accepted design", due to its prevalence in many "popular languages" like PHP/Javascript/etc. An alternative approach which solves the same problem is `match`, as used by ML. However, ML is not a popular language, and ML also introduced currying which you say "read[s] like horrible code". Does that make `switch` better than `match`?

This is an interesting example since a recent Python Enhancement Proposal is trying to add `match` to the language. This proposal seems credible, since the author list includes Guido van Rossum (the creator of Python): https://www.python.org/dev/peps/pep-0622

Perhaps this is an outlier, since Python doesn't already have an equivalent like `switch`?

I wonder if the existence of that PEP changes your opinion of `switch` versus `match`? Maybe not; after all, Python doesn't have `switch` so maybe `match` is better than nothing. What if I showed you an equivalent proposal for adding it to Javascript (using the keyword `case`, like the non-popular language Haskell)? https://github.com/tc39/proposal-pattern-matching

At what point does a feature go from "horrible code" to "stealing each others' best ideas"?

What makes this even more interesting is that the very first sentence of PEP622 makes it clear that this is a case of stealing a good idea:

> This PEP proposes to add a pattern matching statement to Python, inspired by similar syntax found in Scala and many other languages.

To add a further wrinkle, PEP3103 was rejected for proposing essentially the same idea back in 2006: https://www.python.org/dev/peps/pep-3103/

Perhaps it was too soon to adopt ideas from Scala, since it had only been out for a couple of years by that point. However, `match` wasn't invented by Scala; it's been around in multiple languages, some more popular than others, dating back to 1973!

As further evidence of this, there was another rejected PEP for the same basic idea, from way back in 2001: https://www.python.org/dev/peps/pep-0275

I wonder whether your line of reasoning would come out in in favour of PEP622 today, whether it would have come out in favour of PEP275 twenty years ago, and whether it will argue in favour of `match` twenty years from now?