There's already such a language, it's called Haskell and it only allows one parameter per function.
I'd probably be in favor of a hard cap on # of function arguments. :)
(There's also another another option, which is to have a different function for each combination of parameters. This obviously doesn't scale in the large, but it's perfectly acceptable for functions that take only a single optional parameter, which IME is a plurality of APIs that want optional parameters).
With my language-nerd hat on...
While they may seem basic as a user, designing a language means you need to think about edge-cases. Methods in Rust have some special rules around dispatch, and in order to implement one or both of these features, all of that stuff needs to be considered and designed.
In other words, a lot of work goes into new features, even ones that are easy to use.
In Rust's case, we haven't ruled out adding these features completely, but nobody has put in that work to come up with a proposal. Part of that is that while people tend to see the lack of these features as a mild annoyance, it's not enough to prioritize over other work. We'll see how it all shakes out.
> nobody has put in that work to come up with a proposal.
Features like this mainly need a champion who really cares about getting it into the language & can work with the language & compiler teams to complete that process.
#[derive(Default)]
struct Config {
interesting_thing: bool,
a: i32,
b: i32,
c: i32,
}
fn main() {
Config {
interesting_thing: true,
..Config::default()
};
}
In addition, the builder pattern is especially useful for larger configuration objects like this.https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot...
I count about 40 plus more which are not listed.
You surely could first make a dictionary or structure and fill it with these arguments. But then "kwargs" are just that, a dictionary.
I find the interface of the plot function pretty straightforward. There are a lot of options but it's pretty clear what they do and when to use them. Most often you use only some of them - but often different combinations. Splitting this up into multiple helper objects that need to be constructed and filled beforehand would turn the default one-liner into a ten-liner which is not better.
Maybe Ruby on Rails is an exception, but while I used to be a fan of default/keyword arguments, especially in combination, seeing how they were used there made me very much not like them any more. It's impossible to tell what's going on.
It's very clear there...
Similarly, in Swift, the order of defaulted arguments is significant. So you wouldn't see anyone do something like that crazy matplotlib method in Swift, because remembering the order of all the arguments in that function is impractical.
These interfaces are poorly designed; as in natural language, you almost never need more than a subject, direct object, and one or two indirect objects, any of which may themselves be compound entities.
A call with more than about four parameters has usually decomposed at least one thing that should be composite in the argument list.
1) More readable code. The classic is foo.Bar(true). It breaks the flow of reading to have to hover and see what that 'true' means. Much nicer to see foo.bar(launchMissiles: true).
2) Protects from a particular class of dumb mistakes. You have a function foo(x, y) where x and y have the same type. You refactor it so that one of the parameters isn't needed anymore. It's surprisingly easy (read: I've seen it, and I've done it), when you clean up the function calls, to accidentally delete x instead of y or vice-versa. Named parameters prevent that.
This is a case where I've started using Enums in Java. For example:
foo.bar(LaunchMissiles.YES);
In Rust, you could have a macro to make defining these types easier (and have it automatically generate to_bool and from_bool methods): named_bool!(LaunchMissiles);
foo.bar(LaunchMissiles::Yes);Please tell me you're not responsible for this monstrosity https://salilab.org/modeller/9.18/manual/node315.html
[1] https://doc.rust-lang.org/std/default/trait.Default.html
Some consider it a counterpattern or bad memory to be able to not fill out all parameters or reference them by name. However some interfaces easily require like 50 different function parameters that cannot be removed in a simple way and they all make sense in different configurations. Without default values and named parameters you're lost there. I don't get this design decision on Rust side at all.