Overall, I agree with other posters: this RFC needs to be way more bulletproof. Named arguments are always strongly controversial (I think the civil war on the dlang forums is still ongoing), so any proposal needs to be well defended.
The major contention points I'm aware of are:
- Semver implications.
- Generally speaking, if you add named arguments to your functions and then change the names, you're breaking semver. This is something some people are very worried about, because they're concerned that named arguments will be on-by-default, which means they'll be locked into name choices by an external decision; your proposal is opt-in, and doesn't have this problem, which you should emphasize.
- Even then, some people have a knee-jerk reaction against any change adding semver "attack surface", so you could probably add a disclaimer that goes "this adds a semver constraint that names stay the name, but it's a kind of constraint that already exists with struct fields".
- Also, the "arg name vs arg pattern" distinction mitigates the above problem, which is something you should draw attention to.
- There is a trade-off between enforcing that named argument be passed with their names, or allowing them to be passed as positional. Enforcing "namefulness" makes the style more consistent, but the benefits of that are dubious. Allowing positional use of named arguments allows existing APIs to switch to named arguments without breaking semver, which is good for adoption. Personally, I don't think the compiler should worry about style consistency; this should be a clippy lint at most.
- Expressiveness
- A common objection to named arguments is that they don't improve expressiveness/readability compared to other existing or proposed features, such as enums and structural records. For instance, it's often pointed out that the following:
could instead be written asWindow::new(.title = "Hello", .w = 300, .h = 200)
The proposal should demonstrate why these existing features aren't adequate for many use cases.Window::new(Window::Title("Hello"), Window::Size(300, 200))
- Another common substitute for named arguments is the builder pattern. Personally, I find it absolutely ugly, but it's an accepted pattern for languages where named arguments aren't available. The proposal should explain why named arguments provide strong added value over that pattern. (mhh... I'm thinking I might post an article about this on medium at some point)
- A common objection to named arguments is that they don't improve expressiveness/readability compared to other existing or proposed features, such as enums and structural records. For instance, it's often pointed out that the following:
- Language direction
- People discussing named arguments are sometimes worried that they might encourage bad coding practices. The idea is that, by adding optional expressivity features to the language, we might make the language less expressive for people who don't use that feature. Eg:
might be replaced by an API likeselect_until(savedCursor)
but careless users might instead useselect(.until: savedCursor)
which is less explicit for people reading the code. In practice, these concerns can probably be somewhat tempered by including formatting guidelines in the proposal, with some examples.select(savedCursor)
- There's a general undercurrent in a lot of discussions of "is this really worth lang team effort, given that newtypes / the builder pattern / structural records / IDE annotations already exist?" I think part of the process of championing named arguments is to record existing support of the notion, and frontload that support to remind everyone that, yes, this is something people want.
- People discussing named arguments are sometimes worried that they might encourage bad coding practices. The idea is that, by adding optional expressivity features to the language, we might make the language less expressive for people who don't use that feature. Eg:
All that being said, the more I write about this, the more I think this is a debate that can only be solved by the lang team.
There's already been way too much bikeshedding. What the community needs now is for the lang team to do one of three things:
- Declare "we want the feature to be implemented, and we will implement it this way, for these reasons". I think there's a lot of trust in the lang's team design decisions, and if they pick a design the bikeshedding will mostly stop.
- Declare: "we probably want the feature to be implemented, but we're not sure about X and Y; there are multiple possibilities, but in the end we want X and Y to be designed in a way that meets criteria A, B and C"; then focus discussion on criteria A, B and C.
- Decide that named arguments aren't a priority, and any named argument proposal during the next N months/years will be automatically rejected.
This feels like a good fit for the MCP process.