summaryrefslogtreecommitdiff
path: root/src/blog/named-optional-args.kuht
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-09-05 21:29:35 -0400
committerMica White <botahamec@outlook.com>2026-09-05 21:29:35 -0400
commit5ec2d93446ae890e164dd8ad33602a09c0d8814e (patch)
tree6e863c1f7add4f6d682b280f4d9d18669fcc750b /src/blog/named-optional-args.kuht
First commit
Diffstat (limited to 'src/blog/named-optional-args.kuht')
-rw-r--r--src/blog/named-optional-args.kuht1701
1 files changed, 1701 insertions, 0 deletions
diff --git a/src/blog/named-optional-args.kuht b/src/blog/named-optional-args.kuht
new file mode 100644
index 0000000..7d36972
--- /dev/null
+++ b/src/blog/named-optional-args.kuht
@@ -0,0 +1,1701 @@
+<import "base.kuht" as "base" />
+
+<head>
+ <title>Named and Optional Arguments are Awesome</title>
+ <meta name="description" content="Whenever someone asks what my least favorite part of Rust is, my answer is always the same: it doesn't have named or optional arguments. This article explores the ideas for adding them, both good and bad." />
+</head>
+
+<body>
+
+<article>
+
+<h1>Named and Optional Arguments are Awesome</h1>
+
+<p>
+ Whenever someone asks what my least favorite part of Rust is, my answer is
+ always the same: it doesn't have named or optional arguments.
+</p>
+
+<p>
+ I have a small list of programming languages I tolerate: Rust, C#, TypeScript,
+ Dart, Python. Of those languages, Rust is the hardest to get named arguments
+ out of. I'm going to start this post by going over the other languages and how
+ they've achieved named arguments. Then, we'll look at Rust, the problems that
+ have resulted from not having named arguments, and proposals for how Rust
+ could get them in the future.
+</p>
+
+<h2>How Other Languages Handle Named Parameters</h2>
+
+<h3>Dart</h3>
+
+<p>
+ Dart is designed specifically for graphical user interfaces. GUI components
+ tend to have lots of optional parameters, so Dart tried very hard to get them
+ right. And I think it does the best job out of any language we're going to
+ talk about today.
+</p>
+
+<p>
+ First, let's look at a normal function, just to familiarize ourselves with the
+ language:
+</p>
+
+<pre>
+Widget Text(String text) {
+ // ...
+}
+</pre>
+
+<p>
+ That's pretty normal as far as languages go. You can probably guess what it
+ does, even if you don't know Dart. Dart was basically designed in a lab to be
+ easy for programmers to learn.
+</p>
+
+<p>
+ Now, let's add a named parameter to set the size of the text, and default it to
+ 16 pixels:
+</p>
+
+<pre>
+Widget Text(String text, {int fontSize = 16}) { /* ... */ }
+
+// usage:
+Text("Hello, world!", fontSize: 24)
+</pre>
+
+<p>
+ Named parameters are wrapped in curly braces. This makes them look similar to
+ a map. Named parameters can also be defaulted to null, or even required.
+</p>
+
+<pre>
+Widget Text({
+ int fontSize = 16,
+ Color? color,
+ required String text,
+});
+</pre>
+
+<p>
+ Dart also supports optional positional arguments by wrapping the parameter in
+ square brackets.
+</p>
+
+<pre>
+// From the Dart documentation
+String say(String from, String msg, [String device = 'carrier pigeon']) {
+ var result = '$from says $msg with a $device';
+ return result;
+}
+
+assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');
+assert(say('Bob', 'Howdy', 'smoke signal') == 'Bob says Howdy with a smoke signal');
+</pre>
+
+<h3>C#</h3>
+
+<p>
+ C#'s handling of named parameters is also pretty good. In fact, any parameter can be
+ named.
+</p>
+
+<pre>
+void ExampleMethod(string foo, string bar)
+{
+ Console.WriteLine($"{foo} {bar}")
+}
+
+ExampleMethod(bar: "Hello", foo: "world");
+</pre>
+
+<p>
+ And any parameter can have a default value, as long as they're specified after
+ the required parameters.
+</p>
+
+<pre>
+void ExampleMethod(string foo, string bar = "world")
+{
+ Console.WriteLine($"{foo} {bar}")
+}
+
+ExampleMethod("Howdy");
+</pre>
+
+And that's all there is to it. I like the simplicity of it.
+
+<h3>TypeScript</h3>
+
+<p>
+ TypeScript's handling of named parameters is not very good, in my opinion.
+ But optional positional parameters aren't named, and they work pretty well, so
+ let's start with that.
+</p>
+
+<pre>
+function example(required: string, optional?: string = "world"): string {
+ return `${required} ${optional}`;
+}
+
+example("Hello") === "Hello world";
+example("Hello", "TypeScript") === "Hello TypeScript";
+</pre>
+
+<p>
+ That seems fine to me. If you don't specify the default value, then it gets
+ set to <code>undefined</code>. The problem is that there isn't a good built-in
+ syntax for named parameters, so we have to use other TypeScript features to
+ hack it in.
+</p>
+
+<pre>
+function example(
+ required: string,
+ {
+ requiredNamed,
+ namedOptional = "world"
+ }: { requiredNamed: string, namedOptional?: string }
+): string {
+ return `${required} ${requiredNamed} ${namedOptional}`;
+}
+
+example("Hello", { requiredNamed: "beautiful" });
+</pre>
+
+<p>
+ Here, we're taking advantage of both anonymous types and destructuring. The
+ second parameter of the function has an anonymous object type, which contains
+ two fields: <code>requiredNamed</code> and <code>namedOptional</code>. Then
+ we destructure this parameter so we can use the fields in the function.
+</p>
+
+<p>
+ The most annoying part of this is that we have to define the field names
+ twice. Once for the type, and once for the function parameters. This is
+ unnecessary verbosity that any good language should try to avoid. The function
+ call is also more verbose than necessary, because of the curly braces.
+</p>
+
+<p>
+ Unfortunately, this syntax is used all of the time in React. Components are
+ typically a function that takes one argument, which is an object. So when you
+ define a component, you have to do this constantly.
+</p>
+
+<h3>Rust</h3>
+
+<p>
+ Some people have tried to do named parameters in Rust. This generally doesn't
+ work very well. The most common approach is to define a struct for the
+ function, and then have it implement the <code>Default</code> trait, so that
+ we can end the struct initializer with <code>..Default::default()</code>.
+</p>
+
+<pre>
+struct ExampleParams {
+ foo: String,
+ bar: String,
+}
+
+impl Default for ExampleParams {
+ fn default() -> Self {
+ Self {
+ foo: "Hello".into(),
+ bar: "Hello".into(),
+ }
+ }
+}
+
+fn example(Example { foo, bar }) -> String {
+ format!("{foo} {bar}")
+}
+
+assert_eq!(
+ example(Example { foo: "Hello".into(), ..Default::default() }),
+ "Hello world".to_string()
+);
+</pre>
+
+<p>
+ I complained before about how verbose TypeScript's version is, but this is
+ even worse, because the types are not anonymous. And worse, if your default
+ values are not the default of the types (e.g. empty string for <code>String</code>),
+ then you need to write a whole function to set the default values. It also
+ only works if every single parameter has a default value. If only some of the
+ parameters have default values, then you need an even more verbose solution.
+</p>
+
+<h2>Why Rust Needs Optional Parameters</h2>
+
+<p>
+ The standard library doesn't tend to follow the above pattern (for good reason,
+ in my opinion). But there are still several cases where the standard library
+ probably would have benefitted from it.
+</p>
+
+<p>Take some of the factories of <code>HashMap</code>, for example.</p>
+
+<pre>
+impl&lt;K, V> HashMap&lt;K, V, RandomState> {
+ pub fn new() -> HashMap&lt;K, V, RandomState>;
+ pub fn with_capacity(capacity: usize) -> HashMap&lt;K, V, RandomState>;
+}
+
+impl&lt;K, V, A: Allocator> HashMap&lt;K, V, RandomState, A> {
+ pub fn new_in(alloc: A) -> Self;
+ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self;
+}
+
+impl&lt;K, V, S> HashMap&lt;K, V, S> {
+ pub const fn with_hasher(hash_builder: S) -> HashMap&lt;K, V, S>;
+ pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap&lt;K, V, S>;
+}
+
+impl&lt;K, V, S, A: Allocator> HashMap&lt;K, V, S, A> {
+ pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self;
+ pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self;
+}
+</pre>
+
+<p>
+ With just three optional parameters, we need eight functions to represent all
+ of the overloads. Each one of them needs to have their own name, since Rust
+ doesn't actually have overloads. And the programmer and/or code reviewer must
+ either memorize or look up the order of the parameters when one of the more
+ complex factories are used.
+</p>
+
+<p>
+ Another problem that comes up is the fact that, when the parameters are
+ unnamed, it can be easier to make mistakes. Consider the following print
+ function.
+</p>
+
+<pre>
+fn print(text: &str, bold: bool, italics: bool, underline: bool);
+</pre>
+
+<p>
+ It's easy to mix up the parameters here because they don't have names. If I
+ forget that the <code>italics</code> parameter is third and not second, then I
+ can end up accidentally bolding my text instead.
+</p>
+
+<p>
+ Some functions just have lots of parameters as well. Imagine if I added color,
+ underline color, background color, blinking text, hidden text, circled text,
+ and fast blinking text above. Nobody wants to pass in 14 arguments to a
+ function, of which several will have sensible defaults. And I don't see much
+ reason to name a new struct if it's only going to be used for the one function.
+</p>
+
+<h2>Proposals for Named Arguments</h2>
+
+<p>
+ First I'm going to describe some proposals that I've seen for improving named
+ arguments in Rust, that I don't like. Then I'll reveal what my preferred
+ solution is.
+</p>
+
+<h3>Default Field Values</h3>
+
+<p>
+ This feature is already available in Nightly Rust. And the <code>syn</code>
+ create even recently added support for it. The idea is to make implementing
+ the <code>Default</code> trait easier by adding special syntax for it. It's
+ not proposed that this will solve named arguments by itself, but might be part
+ of a larger solution.
+</p>
+
+<pre>
+#[derive(Default)]
+struct Pet {
+ name: Option&lt;String>, // impl Default for Pet will use Default::default() for name
+ age: i128 = 42, // impl Default for Pet will use the literal 42 for age
+}
+
+// Pet { name: Some(""), age: 42 }
+let _ = Pet { name: Some(String::new()), .. };
+// Compilation error: `name` needs to be specified
+let _ = Pet { .. };
+// Pet { name: None, age: 42 }
+let _ = Pet::default();
+</pre>
+
+<p>
+ I don't actually have a problem with the proposal itself. I even created my
+ own library to implement a polyfill for it
+ (<a href="https://www.lib.rs/feluments">feluments</a>). It seems perfect for
+ structs. But it doesn't help very much for functions.
+</p>
+
+<h3>Structural Records</h3>
+
+<p>
+ The RFC for default field values mentions a closed RFC for structural records.
+ They can be thought of as anonymous structs or tuples with named fields.
+</p>
+
+<pre>
+fn do_stuff_with(color: { red: u8, green: u8, blue: u8 }) { // More ergonomic!
+ some_stuff(color.red); // *And* readable! :)
+ ...
+ other_stuff(color.green);
+ ...
+ yet_more_stuff(color.blue);
+}
+
+do_stuff_with({ red: 255, green: 127, blue: 63 });
+</pre>
+
+<p>
+ The RFC notes that this emulates named arguments, although it does not emulate
+ optional arguments. It wasn't a major motivation. The major motivation was to
+ get the convenience of tuples with the readability of structs.
+</p>
+
+<p>
+ Let's say for the sake of argument that this RFC succeeded. What would the
+ syntax of our "Hello, world" examples look like here? Let's assume default
+ field values are also merged, and they work with structural records.
+</p>
+
+<pre>
+fn example(
+ required: String,
+ {requiredNamed, namedOptional}: {
+ requiredNamed: Option&lt;String>,
+ namedOptional: String = "world".into()
+ }
+): String {
+ format!("{required} {requiredNamed} {namedOptional}")
+}
+
+example("Hello", { requiredNamed: "beautiful", .. });
+</pre>
+
+<p>
+ Wow, that looks familiar. In fact it's the same syntax that TypeScript uses,
+ with all the problems that come with it. You need to specify the parameter
+ names twice.
+</p>
+
+<p>Structural records also come with many other challenges:</p>
+<ul>
+ <li>
+ What happens with records that have only one field? <code>{ x }</code> can be
+ interpreted as either a block expression that returns <code>x</code>, or a
+ structural record expression: <code>{ x: x, }</code>. To fix the ambiguity,
+ the RFC proposed requiring an extra comma: <code>{ x, }</code>, like what
+ tuples do. But this requires making the Rust parser much more complicated,
+ to do several tokens of lookahead.
+ </li>
+ <li>
+ It's impossible to implement any traits on these. The RFC proposed magically
+ implementing several traits. And unlike for tuples, we can't just define some
+ generic trait implementations, because there can be so much variation in the
+ field names.
+ </li>
+ <li>
+ A newcomer to the language may mistake this syntax for a Python dictionary
+ or Dart's map type.
+ </li>
+</ul>
+
+<p>
+ Interestingly, TypeScript actually has named tuple fields. But they only exist
+ at the type declaration. You can't use the field names to access the fields.
+</p>
+
+<pre>
+type NewLocation = [lat: number, long: number]
+
+const newLocations: NewLocation[] = [
+ [52.3702, 4.8952],
+ [53.3498, -6.2603]
+]
+
+const firstLat = newLocations[0][0]
+const firstLong = newLocations[0][1]
+</pre>
+
+<p>
+ Rust's language team decided that although something resembling this feature
+ seems useful, it would be very hard to implement and not worth the effort.
+</p>
+
+<h3>Copy C#</h3>
+
+<p>
+ If we're already agreeing on a syntax for optional fields in structs, why not
+ just copy that over to functions? First, we can allow the arguments to be
+ specified in any order, as long as they are named, and no out-of-order
+ positional arguments are following a named argument.
+</p>
+
+<pre>
+print_order_details(order_num: 31, product_name: "Red Mug", seller_name: "Gift Shop");
+print_order_details(seller_name: "Gift Shop", product_name: "Red Mug", order_num: 31);
+print_order_details("Gift Shop", 31, product_name: "Red Mug");
+print_order_details(seller_name: "Gift Shop", 31, product_name: "Red Mug");
+
+// this would cause an error
+print_order_details(product_name: "Red Mug", 31, "Gift Shop");
+</pre>
+
+<p>
+ Then, we could define default values, and allow parameters with default values
+ to be unspecified.
+</p>
+
+<pre>
+fn print_order_details(product_name: &str, order_num: 31, seller_name: &str = "Gift Shop");
+
+print_order_details("Red Mug", 31);
+</pre>
+
+<p>
+ Unlike for the default field values proposal, we can't use a <code>..</code>
+ at the end here, because it is also a valid expression.
+</p>
+
+<p>
+ The biggest problem with this idea is that it makes parameter names part of
+ the public API of the function, without functions opting into it. There was
+ previously an objection on the grounds of it conflicting with the proposed
+ type ascription feature. But the RFC for it has since been deleted, so I don't
+ think we need to worry about that anymore.
+</p>
+
+<h3>Public Arguments</h3>
+
+<p>
+ As far as I know, a formal RFC was never made for this, but a pre-RFC was
+ posted to the Rust Internals Forum several years ago, and it's the most
+ thorough proposal for named arguments that I know of. I'll avoid copy-pasting
+ the entire RFC here, but I'll give a high level overview.
+</p>
+
+<p>Here's an example of a function with named arguments from the RFC:</p>
+
+<pre>
+pub struct Database;
+pub struct RegistrationError;
+
+pub fn register(
+ pub name: String,
+ pub surname: String,
+ to db: Database
+) -> Result&lt;(), RegistrationError> {
+ /* ... */
+}
+
+register(name: "Alexis".into(), surname: "Poliorcetics".into(), to: my_db);
+</pre>
+
+<p>
+ In the case of <code>to db</code>, the name of the argument is <code>to</code>,
+ but it's referred to as <code>db</code> within the body of the function. For
+ the other two parameters, the <code>pub</code> keyword is used to say that
+ that both the name of the argument when calling the function, and the name of
+ the parameter in the function body, are the same.
+</p>
+
+<p>
+ The RFC goes into way more detail, proposing function overloads, using named
+ arguments with the <code>Fn</code> trait, exposing names from patterns, method
+ overloads, and explaining the documentation aspect.
+</p>
+
+<p>Here are the criticisms I saw in the comments:</p>
+<ul>
+ <li>
+ Unordered named arguments was ruled out. I don't like the justification
+ RustyFrog gave for this, but it seems easy to support with this model.
+ </li>
+ <li>
+ Default parameter values also weren't proposed, even though it's the main
+ reason for wanting named parameters
+ </li>
+ <li>
+ Despite not proposing default parameter values, the pre-RFC did propose
+ overloads, which are very difficult to implement in Rust, and they're not as
+ useful as optional arguments. It's not proposing type-based overloads, which
+ is a bit better, but still.
+ </li>
+ <li>It's a very big RFC, which might make it difficult to get it approved.</li>
+ <li>
+ There are some syntax ambiguities, like <code>fn foo(name (a, b): name)</code>,
+ which is currently valid syntax. There was also a proposed type acription
+ feature that it conflicted with, but as I said before, that RFC has since
+ been removed.
+ </li>
+ <li>
+ Using <code>pub</code> might be confusing, given how it's used currently. I
+ don't think I mind that personally, because its effect is to make the name of
+ the parameter part of a function's public API. But I get how that's a bit
+ weird.
+ </li>
+ <li>
+ The proposal for changing the <code>Fn</code> trait seemed underbaked. The
+ <code>Fn(f32, f32) -> String</code> trait gets desugared to
+ <code>Fn&lt;(f32, f32), Output = String></code>, but it's not clear what the
+ desugaring for named parameters should look like.
+ </li>
+ <li>
+ Despite explaining the usage for <code>Fn</code> implementations, the <code>fn</code>
+ type was not mentioned at all.
+ </li>
+ <li>
+ The pre-RFC was not clear about if named parameters were required to be used
+ by name, or if having the correct position was technically sufficient.
+ </li>
+ <li>
+ The handling of extern functions with named arguments is fairly complicated
+ to the point where it would probably be better to not handle them.
+ </li>
+</ul>
+
+<p>
+ My understanding is that the author got busy and didn't address these concerns,
+ but I think the pre-RFC serves as a good starting point.
+</p>
+
+<h3>Struct-style function calls</h3>
+
+<p>
+ This idea was proposed back in 2016 by nixpulvis. I've also seen it floating
+ around in some other places.
+</p>
+
+<pre>
+// 1. Tuple style method call (current functions).
+fn foo(a: u32) {}
+foo(2);
+
+// 2. Struct style method call.
+fn foo { a: u32 }
+foo { a: 2 };
+// SomeType { a: 1 } -> SomeType
+// SomeFunc { a: 1 } -> Codomain
+// generally_lowercase { a: 1 } -> Codomain
+
+// 3. Together.
+fn foo(a: u32) { a: u32 } {}
+foo(1) { a: 2 };
+</pre>
+
+<p>
+ I personally don't like it because it makes struct constructions and function
+ calls look too similar. I also have no idea how the compiler would parse this.
+ But then again, most languages use <code>new Foo()</code> syntax for
+ constructors, so maybe somebody will like it.
+</p>
+
+<h3>Copy Dart</h3>
+
+<p>
+ Another proposal that's come up, including from myself, is to copy the Dart
+ syntax, like so:
+</p>
+
+<pre>
+fn foo({ foo: &str = "Hello", bar: &str = "World" }) -> String {
+ format!("{foo} {bar}")
+}
+</pre>
+
+<p>
+ To me, this looks too much like existing pattern syntax. But I do like that it
+ doesn't require an extra keyword on each argument.
+</p>
+
+<h3>Edition Separation</h3>
+
+<p>
+ Some people have proposed solving the backwards-compatibility problem by only
+ allowing named arguments to be used with functions that were written in a
+ future edition of Rust. To me, this feels like too large of a breaking change
+ to be worth considering.
+</p>
+
+<h3>Dot Prefixes</h3>
+
+<p>
+ An RFC was opened in 2020 proposing using a dot prefix to distinguish between
+ named and unnamed variables. It was not merged, because the RFC was a very
+ incremental step that didn't explain the future plans for how the named
+ arguments would work. Here's an example from the PR:
+</p>
+
+<pre>
+fn split(string: &str, .at: char, .limit: usize, .case_sensitive: bool) {}
+
+split("hello world", .at = ' ', .limit = 2, .case_sensitive = true);
+</pre>
+
+<p>
+ The dot was chosen because it's only one character, (as opposed to four
+ characters, with the <code>pub</code> keyword plus a space). But I honestly
+ don't think it's intuitive enough. The dot is also reminds the user of struct
+ fields, which is a completely unrelated concept.
+</p>
+
+<h2>My Proposal</h2>
+
+<p>
+ After reading all of these proposals, I feel that all of the pieces exist for
+ a complete named arguments proposal that lack any of the downsides. I get the
+ impression that some people are going to be opposed to the concept no matter
+ what, but I tried to address as many counter-arguments for named arguments as
+ possible in this post. The rest of this post will be a pre-RFC that think
+ will satisfy as many people as possible. I'll monitor the comments anywhere
+ this gets posted to see if there are any major criticisms. I can't guarantee
+ that I'll actually make an RFC, but permission is granted to create an RFC if
+ I don't. I think it's been a while since named argument were last seriously
+ proposed, so I think now is a good time for a new proposal.
+</p>
+
+<h3>Summary</h3>
+
+<p>
+ Add named and optional arguments to functions. Functions can have both
+ positional and named arguments. In function calls, named arguments may be
+ referred to by name, to increase readability and maintainability. Named
+ arguments may also have default values, avoiding the need to specify them in
+ the function call.
+</p>
+
+<h3>Motivation</h3>
+
+<h4>Improve safety and readability</h4>
+
+<p>
+ Misremembering which parameter is at which position is a major source of bugs
+ in many languages, including Rust. Take the function from the standard
+ library: <code><a href="https://doc.rust-lang.org/stable/std/fs/fn.hard_link.html">hard_link</a></code>.
+</p>
+
+<pre>
+pub fn hard_link&lt;P: AsRef&lt;Path>, Q: AsRef&lt;Path>>(
+ original: P,
+ link: Q,
+) -> Result&lt;()>
+</pre>
+
+<p>
+ Both parameters accept the same types, so there's no way to know which one is
+ which without looking at the documentation. The consequence of misremembering
+ is a runtime error or a bug.
+</p>
+
+<p>
+ With named parameters, it is easy to see what is happening at the call-site.
+ This also makes the resulting code more readable.
+</p>
+
+<pre>
+hard_link(original: "a.txt", link: "b.txt")?;
+</pre>
+
+<p>The effect is more pronounced for functions which have more parameters.</p>
+
+<pre>
+// Without named arguments: what are these numbers?
+solar_elevation(1787517098.0, 38.897957, -77.036560)
+
+// With named arguments, it's obvious
+solar_elevation(timestamp: 1787517098.0, latitude: 38.897957, longitude: -77.036560);
+</pre>
+
+<p>
+ A similar effect is possible in Rust today, by creating a new struct and
+ having that be the function's only parameter. But it's very verbose to create,
+ so in practice, few libraries take advantage of it. Importantly, the standard
+ library rarely uses this pattern.
+</p>
+
+<h4>Boilerplate reduction</h4>
+
+<p>
+ Many functions have reasonable defaults that should be passed into many of
+ their parameters, but because all positional arguments are required, all of
+ the parameters must be specified. Passing <code>None</code> into every
+ parameter comes with readability issues.
+</p>
+
+<pre>
+repository.checkout_index(None, None)?;
+</pre>
+
+<p>
+ Passing a struct into the parameters does give us names, but still requires
+ us to specify <code>None</code> for the optional values. Sometimes this
+ boilerplate can be reduced by adding <code>..Default::default()</code> to the
+ end of the constructor, <code>Default</code> cannot be implemented if any of
+ the fields are not optional. Implementing <code>Default</code> is also a lot
+ of boilerplate if it cannot be implemented simply by using the derive macro.
+ Some of these problems can be addressed by
+ <a href="https://github.com/rust-lang/rfcs/pull/3681">RFC 3681</a>, but it
+ still requires a new struct to be defined specifically for one function.
+</p>
+
+<pre>
+let instance = Instance::new(InstanceDescriptor {
+ backends: Backends::default(),
+ flags: InstanceFlags::default(),
+ memory_budget_thresholds: MemoryBudgetThresholds::default(),
+ backend_options: BackendOptions::default(),
+ display: None,
+});
+</pre>
+
+<p>
+ To help reduce the boilerplate of calling such a function, many libraries
+ implement builder types that don't require every value to be specified. This
+ comes at the cost of even more boilerplate to create the builder, which
+ becomes part of the library's public API. There are crates, such as
+ <a href="https://www.crates.io/crates/bon">bon</a> to make declaring a builder
+ for a struct easier, but it still requires a struct be declared for a single
+ function. Libraries don't always use these crates either, as doing so
+ increases compile times. The <code>Command</code> struct uses 60 SLOCs (and
+ many more lines of documentation) to allow us to do this:
+</p>
+
+<pre>
+Command::new("printenv")
+ .stdin(Stdio::null())
+ .stdout(Stdio::inherit())
+ .env_clear()
+ .envs(&filtered_env)
+ .spawn()
+ .expect("printenv failed to start");
+</pre>
+
+<p>If we had named arguments, the following function would be easy to define:</p>
+
+<pre>
+spawn(
+ command: "printenv",
+ stdin: Stdio::null(),
+ stdout: Stdio::inherit(),
+ env_clear: true,
+ envs: &filtered_env
+).expect("printenv failed to start");
+</pre
+
+<p>
+ Bon also provides utilities for emulating named arguments in functions, but
+ calling such a function involves some boilerplate as well.
+</p>
+
+<pre>
+// Example from the bon README
+
+#[builder]
+fn greet(name: &str, level: Option&lt;u32>) -> String {
+ let level = level.unwrap_or(0);
+
+ format!("Hello {name}! Your level is {level}")
+}
+
+// This could be shortened to greet(name: "Bon", level: 24)
+let greeting = greet()
+ .name("Bon")
+ .level(24)
+ .call();
+
+assert_eq!(greeting, "Hello Bon! Your level is 24");
+</pre>
+
+<p>
+ In practice, the added complexity means that these patterns are only ever used
+ in public APIs, so private functions have no worthwhile workaround to improve
+ readability.
+</p>
+
+<h4>Extensibility without breaking changes</h4>
+
+<p>
+ Currently, adding a new parameter to an existing function is a breaking
+ change. If you want to add a new field to a struct, your existing factory must
+ implement a reasonable default value, and a new function must be created to
+ enable the new functionality.
+</p>
+
+<p>
+ This leads to some APIs having many functions which do similar things, but
+ with different parameters. For example, <code>HashMap</code> from the standard
+ library has the following factories.
+</p>
+
+<pre>
+impl&lt;K, V> HashMap&lt;K, V, RandomState> {
+ pub fn new() -> HashMap&lt;K, V, RandomState>;
+ pub fn with_capacity(capacity: usize) -> HashMap&lt;K, V, RandomState>;
+}
+
+impl&lt;K, V, A: Allocator> HashMap&lt;K, V, RandomState, A> {
+ pub fn new_in(alloc: A) -> Self;
+ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self;
+}
+
+impl&lt;K, V, S> HashMap&lt;K, V, S> {
+ pub const fn with_hasher(hash_builder: S) -> HashMap&lt;K, V, S>;
+ pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap&lt;K, V, S>;
+}
+
+impl&lt;K, V, S, A: Allocator> HashMap&lt;K, V, S, A> {
+ pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self;
+ pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self;
+}
+</pre>
+
+<p>
+ All of these functions are shown in the documentation, polluting the API. The
+ number of functions is exponential with respect to the number of parameters.
+ If we ignore the differences in generic parameters (a possible solution to
+ which is discussed in the "Future possibilities" section), then we could
+ imagine having a single function.
+</p>
+
+<pre>
+pub fn new(
+ pub capacity: usize = 0,
+ pub alloc: A = Global,
+ pub hasher: S = RandomState,
+);
+</pre>
+
+<p>
+ If we wanted to some day add a <code>fill</code> parameter, we'd be able to
+ add it to this existing function without it being a breaking change, and
+ without doubling the number of factories for <code>HashMap</code>.
+</p>
+
+<h3>Guide-level explanation</h3>
+
+<p>
+ Parameters may be named or unnamed. By default, all parameters to a function
+ are unnamed, and cannot be referred to by name. We can create a named
+ parameter by adding the <code>pub</code> keyword before its name.
+</p>
+
+<pre>
+fn print_labeled_measurement(pub value: i32, pub unit_label: char) {
+ println!("The measurement is: {value}{unit_label}");
+}
+
+fn main() {
+ print_labeled_measurement(5, 'h');
+}
+</pre>
+
+<p>
+ At first, this may not seem very different from unnamed parameters. But when
+ a parameter is named, we may use its name when calling the function. This
+ makes it easier to tell, at a glance, what the values being passed into the
+ function are meant to do.
+</p>
+
+<pre>
+print_labeled_measurement(value: 5, unit_label: 'h');
+</pre>
+
+<p>
+ When parameters are named, they may also be re-ordered, so you don't need to
+ remember the position of each one.
+</p>
+
+<pre>
+print_labeled_measurement(unit_label: 'h', value: 5);
+</pre>
+
+<p>
+ There are some caveats to the ordering. A function may contain both named and
+ unnamed parameters. But if it does, all named arguments must be specified
+ after the positional arguments, both in the function declaration and in the
+ function body.
+</p>
+
+<pre>
+// unit_label is named, value is not
+fn print_labeled_measurement(value: i32, pub unit_label: char) {
+ println!("The measurement is: {value}{unit_label}");
+}
+
+// forbidden: all named parameters must be after all unnamed parameters
+fn _print_labeled_measurement(pub value: i32, unit_label: char) {
+ // ...
+}
+
+fn main() {
+ // forbidden: the parameter that 'h' is being passed into must be named
+ print_labeled_measurement(value: 5, 'h');
+ // forbidden
+ print_labeled_measurement(unit_label: 'h', 5);
+}
+</pre>
+
+<p>
+ Named parameters may also have default values. This means that the caller does
+ not need to specify the argument value when calling the function. The default
+ value is using automatically.
+</p>
+
+<pre>
+fn print_labeled_measurement(pub value: i32, pub unit_label: char = 'm') {
+ println!("The measurement is: {value}{unit_label}");
+}
+
+fn main() {
+ // unit_label is unspecified and is defaulted to 'm'
+ print_labeled_measurement(5)
+}
+</pre>
+
+<p>
+ Named parameters cannot be used if the parameter does not have a name and is
+ defined as a pattern instead. For example, the following is not valid.
+</p>
+
+<pre>
+fn print_coordinates(pub &(x, y): &(i32, i32)) {
+ // ...
+}
+</pre>
+
+<p>
+ However, a name can be given to this parameter by using an <code>@</code>
+ binding.
+</p>
+
+<pre>
+fn print_coordinates(pub point @ &(x, y): &(i32, i32)) {
+ // ...
+}
+</pre>
+
+<p>
+ Traits may also choose to use named parameters, in which case the
+ implementation must use the same name. However, trait function parameters
+ cannot have default values.
+</p>
+
+<pre>
+trait Trait {
+ fn f(pub a: i32, pub b: i32);
+}
+
+impl Trait for () {
+ // This is okay, because the parameter names match
+ // unused parameter warnings can be ignored using @
+ fn f(pub a: i32, pub b @ _: i32) {}
+}
+
+impl Trait for i32 {
+ // invalid: the second argument is named `b` in the definition
+ fn f(pub a: i32, pub c: i32) {}
+}
+
+impl Trait for bool {
+ // invalid: `b` is not public
+ fn f(pub a: i32, b: i32) {}
+}
+
+impl Trait for X {
+ // invalid: trait methods cannot have default parameter values
+ fn f(pub a: i32, pub b: i32 = 0) {}
+}
+</pre>
+
+<p>
+ Because the parameter names are optional, function pointers may be created for
+ functions with named parameters. However, the name will not be accessible on
+ the function pointer, and default values cannot be used. This also applies for
+ the <code>Fn*</code> family of traits.
+</p>
+
+<pre>
+fn foo(pub a: i32, pub b: i32) {}
+
+let f: fn(i32, i32) = foo;
+
+f(4, 2); // ok
+f(a: 4, b: 2); // ERROR! `f` can't be called with named arguments
+
+fn higher_order(f: Fn(i32, i32)) {
+ f(4, 2); // ok
+ f(a: 4, b: 2); // ERROR! `f` can't be called with named arguments
+}
+higher_order(foo); // ok
+higher_order(|_, _| {}); // ok
+</pre>
+
+<h3>Reference-level explanation</h3>
+
+<h4>Grammar</h4>
+
+<p>
+ The only needed change to support public parameters in function declarations
+ is to function parameters. First, we add the <code>pub</code> keyword, which
+ must be followed by an identifier pattern. Such a pattern may also include a
+ default value.
+</p>
+
+<pre>
+FunctionParamPattern = PatternNoTopAlt ":" ( Type | "..." )
+ | "pub" IdentifierPattern ":" ( Type | "..." ) ( "=" Expr )?
+</pre>
+
+<p>
+ For function calls, the syntax is slightly more complicated to parse, but only
+ affects <code>CallParams</code>.
+</p>
+
+<pre>
+CallParam = Expression ( ":" Expression )?
+CallParams = CallParam ( "," CallParam )* ","?
+</pre>
+
+<p>
+ This is slightly more complicated to parse, because an identifier is also a
+ valid expression. To solve this, we'll just parse an entire expression, and
+ then check to see if there's a colon following it. The compiler can later
+ give an error if the argument name is anything other than an identifier.
+</p>
+
+<h4>Static semantics</h4>
+
+<h5>Function parameters</h5>
+
+<p>
+ Given a <code>FunctionParamPattern</code> where the default is specified, i.e.:
+</p>
+
+<pre>
+FunctionParamPattern = "pub" pat:IdentifierPattern ":" ( ty:Type | "..." ) ( "=" expr:Expr )
+</pre>
+
+<p>similar rules to the rules for default field values apply. Namely,</p>
+<ul>
+ <li>
+ If the function is <code>const</code>, then the expression, <code>expr</code>
+ must be a constant expression.
+ </li>
+ <li>The expression <code>expr</code> must coerce to the type <code>ty</code></li>
+ <li>
+ Generic parameters of the current items are accessible.
+<pre>
+fn foo&lt;const A: usize>(bar: usize = A) {}
+</pre>
+ </li>
+ <li>
+ Default const expressions are not evaluated at definition time, only during
+ instantiation. This means that the following will not fail to compile:
+<pre>
+fn foo(a: usize = panic!(), b: usize = 42) {}
+
+foo(a: 0);
+</pre>
+ </li>
+ <li>
+ The function's generic parameters are properly propagated, meaning the following is possible:
+<pre>
+fn foo&lt;T>(bar: Vec&lt;T> = Vec::new()) {}
+
+foo::&lt;T>();
+</pre>
+ </li>
+ <li>
+ When lints check attributes such as <code>#[allow(lint_name)]</code> are
+ placed on a <code>FunctionParam</code>, it also applies to the expression,
+ <code>expr</code>.
+ </li>
+ <li>
+ Unused parameter names will not emit a warning if they are bound to a
+ different pattern using <code>@</code>. The bound pattern may still emit a
+ warning
+ </li>
+</ul>
+
+<p>
+ For public parameters in general, all public parameters must be strictly after
+ all non-public parameters.
+</p>
+
+<h5>Function calls</h5>
+
+<p>
+ The semantics of function calls change significantly. In general, all named
+ arguments must be specified after all positional arguments. For positional
+ arguments, all existing semantics apply.
+</p>
+
+<p>In the case of the following production of a named argument:</p>
+<pre>
+CallParam = name:Expression ":" value:Expression
+</pre>
+<p>the following rules apply</p>
+<ul>
+ <li>The expression, <code>name</code> must be a plain identifier.</li>
+ <li>
+ The identifier, <code>name</code> must be the name of a public parameter of
+ the function.
+ </li>
+ <li>
+ The expression, <code>value</code> must coerce the the type of the
+ aforementioned public parameter.
+ </li>
+</ul>
+
+<h5>Trait declarations</h5>
+
+<p>
+ For trait declarations all the same rules apply from function declarations. In
+ addition:
+</p>
+<ul>
+ <li>Trait methods cannot have default parameter values.</li>
+</ul>
+
+<h5>Trait implementations</h5>
+
+<p>
+ The semantics of trait implementations vary slightly from the semantics for
+ trait declarations.
+</p>
+<ul>
+ <li>
+ Any parameter which was declared public on the trait declaration must also
+ be public in the trait implementation.
+ </li>
+ <li>Public parameters must have the same name that their declaration has.</li>
+</ul>
+
+<h3>Drawbacks</h3>
+
+<h4>Added complexity</h4>
+
+<p>
+ The language would be slightly more complex as a result of this feature. But
+ this proposal is fairly minimal as far as named arguments proposals go. The
+ syntax for named arguments resembles the syntax for struct fields, and the
+ default value syntax is pretty similar to the syntax proposed for default
+ field values.
+</p>
+
+<p>
+ One concern that can come up in named argument proposals is the problem of it
+ only applying to new functions, which makes it hard to remember which
+ libraries. This proposal can be backported to the standard library, making the
+ language feel more consistent.
+</p>
+
+<h4>Named arguments aren't mandatory</h4>
+
+<p>
+ The fact that names are optional could be seen as a compromise on the safety
+ benefits. Some people may lazily choose to leave them out, in which case, no
+ safety benefit is provided.
+</p>
+
+<p>
+ However, the fact that they aren't mandatory allows more library authors to
+ use them without worrying about breaking changes. Some authors may also be
+ more inclined to support named arguments if they felt confident that it would
+ not increase the verbosity of calling the function.
+</p>
+
+<p>
+ This drawback does present a potential bug. If the names are removed during a
+ refactor, then they may be in the wrong position after the refactor, causing
+ a bug.
+</p>
+
+<pre>
+// before refactor
+coordinates(y: 45.6, x: 6784.0);
+
+// after refactor: incorrect order
+coordinates(y, x);
+</pre>
+
+<h5>Remedy: Add a clippy lint</h5>
+
+<p>
+ A clippy lint can be used to enforce the use of named arguments when possible.
+</p>
+
+<h5>Remedy: Require named arguments in a future edition</h5>
+
+<p>
+ Although it may be a large breaking change, future editions could likely
+ require the use of named parameters, if it were deemed desirable to do so.
+</p>
+
+<h4>Limiting type ascription</h4>
+
+<p>
+ Many older proposals for named arguments noted that the syntax chosen here:
+ <code>name: value</code> conflicts with the proposed type ascription feature.
+ However, since then, the RFC for type ascription has been removed. And another
+ type ascription RFC was rejected, partially on the basis of it potentially
+ conflicting with named arguments. So this is not likely to be a concern
+ anymore.
+</p>
+
+<h3>Rationale and alternatives</h3>
+
+<h4>Why make named arguments opt-in?</h4>
+
+<p>
+ Although many languages, such as Kotlin and C#, allow any argument to be
+ named, this is not practical for Rust. Changing an argument is currently not
+ a breaking change, but would become one as soon as named arguments are
+ introduced. The solution is to allow authors to decide if their argument names
+ are an implementation detail or not.
+</p>
+
+<h4>The <code>pub</code> keyword</h4>
+
+<p>
+ Using the <code>pub</code> keyword may seem like a strange choice, given the
+ semantics. But it has essentially the effect of making the parameter name
+ public, so this is defensible. Other visibility modifiers are not proposed by
+ this RFC, because it's hard to imagine a situation where a public function
+ would want to allow named arguments internally, but not externally.
+</p>
+
+<p>
+ Other modifiers have been proposed. One could imagine adding an <code>ext</code>
+ keyword to define named parameters. A previous RFC proposed using dots, but
+ this was deemed to be too reminiscent of field access. Other symbols, such as
+ <code>@</code> may be more acceptable. Another proposed idea is to copy Swift
+ syntax and use two identifiers.
+</p>
+
+<pre>
+fn foo(bar bar: &str) {}
+</pre>
+
+<p>
+ Re-typing the same parameter name twice is verbose and usually unnecessary.
+ It's also unnecessary since syntax exists for rebinding a variable already.
+</p>
+
+<p>
+ Dart wraps named arguments in curly braces. This has the benefit of not
+ requiring the <code>pub</code> keyword to be specified multiple times. However,
+ in the context of Rust, this looks like a destructuring pattern, which isn't
+ semantically correct.
+</p>
+
+<pre>
+// In Dart
+void enableFlags({bool? bold, bool? hidden})
+enableFlags(bold: true)
+
+// Similar idea, in Rust
+fn enable_flags({ bold: Option&lt;bool> = None, hidden: Option&lt;bool> = None })
+enable_flags(bold: Some(true))
+</pre>
+
+<p>
+ Another proposal is to make function calls with named arguments look more like
+ struct constructions by using curly braces instead of parentheses. This seems
+ like it could be very confusing and make the distinction between the two
+ features unclear.
+</p>
+
+<pre>
+fn foo (a: u32) { b: u32 } {}
+foo(1) { b: 2 };
+</pre>
+
+<h4>Colon vs equal sign</h4>
+
+<p>
+ Some have proposed using an equal sign (<code>=</code>) instead of a colon
+ (<code>:</code>). This would make the syntax more closely resemble assignment,
+ which is semantically true. It also would not possibly conflict with type
+ ascription.
+</p>
+
+<p>
+ The colon syntax was chosen for this RFC to be more consistent with struct
+ initializers.
+</p>
+
+<h4>Argument re-ordering</h4>
+
+<p>
+ Some proposals for named arguments have omitted re-ordering of arguments for
+ simplicity. For the sake of thoroughness, this RFC proposes allowing arguments
+ to be re-ordered. A possible alternative would be to require arguments to
+ still be in the original order. The drawback would be unnecessary friction
+ when the user sorts the arguments out of order.
+</p>
+
+<p>
+ Some languages allow for more flexible re-ordering than this RFC proposes. C#
+ allows named arguments to appear before unnamed arguments, as long as the
+ arguments are still in order. This RFC omits this feature, in order to make
+ named arguments seem less confusing to users. The reordering proposed here
+ still allows for more flexible argument-reordering in the future.
+</p>
+
+<h4>No default values in traits</h4>
+
+<p>
+ This RFC currently prohibits traits from making use of default parameter
+ values. This is because it's unclear if default values for trait parameters
+ should be defined at the trait definition or the trait implementation. It
+ would likely be more predictable if default values could be defined by the
+ implementation. But it's hard to imagine how a default value would allow the
+ trait to be dyn-compatible. If the default values were defined at the trait
+ definition, then they could stay dyn-compatible.
+</p>
+
+<h4>On const contexts</h4>
+
+<p>
+ In the default field values RFC, it was decided that default values for
+ structs must be const. The reasoning is that functions with side-effects may
+ be confusing for the compiler and for users. However, these justifications
+ don't apply to functions, because non-const functions don't carry an
+ expectation of being cheap or consistent. It is possible to always require
+ default values to be const, but there's seemingly no strong reason to do so.
+</p>
+
+<p>
+ However, it would be confusing if default parameters could be non-const in
+ const functions, which is why they are required to be const in that case.
+</p>
+
+<h4>Named arguments aren't mandatory</h4>
+
+<p>See the section above in "Drawbacks".</p>
+
+<h4>Alternative: Do nothing</h4>
+
+<p>
+ The "Motivation" section explains thoroughly how the current state is very
+ verbose, to the point where existing alternatives, such a struct parameters
+ and builders are often not used. The existence of these patterns is evidence
+ that users want some way to emulate named arguments. The fact that these
+ alternatives are not used in private APIs is evidence that the status quo is
+ annoyingly verbose.
+</p>
+
+<h4>Alternative: Structural Records</h4>
+
+<p>
+ It has been proposed many times that structural records, alongside default
+ field values, could emulate named parameters. This is a pattern that is often
+ used in languages like TypeScript. The syntax for declaring such a function
+ would look like this.
+</p>
+
+<pre>
+fn foo({ a, b, c }: { a: f64, b: f64, c: f64 }) {}
+</pre>
+
+<p>There are several criticisms I have of this pattern:</p>
+<ul>
+ <li>
+ It cannot be backported to older functions without causing a breaking change,
+ so the standard library could not use it.
+ </li>
+ <li>
+ Every identifier in this declaration needs to be typed twice. It might be
+ possible to introduce syntactic sugar for this, but not such syntax has been
+ proposed.
+ </li>
+ <li>
+ Structural records have had a proposed RFC in the past, but was rejected,
+ mainly due to the complexity of implementing it.
+ </li>
+</ul>
+
+<p>
+ Structural records could serve as a temporary compromise for named arguments,
+ if they are ever implemented. I'm not currently convinced that they ever will
+ be implemented. If the compromise solution is harder to implement than the
+ real solution, then we might as well just use the real solution.
+</p>
+
+<h4>Alternative: Struct name inference</h4>
+
+<p>
+ One proposal to make named arguments easier is to allow the name of a struct
+ to be inferred when it is constructed. This would make the call sites of
+ functions using struct parameters to look mostly simple.
+</p>
+
+<pre>
+foo(_ { a: 1, b: "2", c: [] });
+</pre>
+
+<p>
+ However, this still requires the function to support this function explicitly,
+ by defining a struct to be passed in. It also still cannot be backported to
+ existing functions. The only benefit this provides over the status quo is to
+ avoid typing the name of the struct at the call site, which is not the main
+ criticism of this pattern. It would still be unlikely for private functions to
+ use this pattern.
+</p>
+
+<h4>Alternative: Implementing <code>Fn</code> traits</h4>
+
+<p>
+ I've seen this come up a couple of times, but I think most of the people
+ suggesting this are doing so as a joke. Implementing <code>Fn</code> would
+ be a more verbose form of the method overload feature that some other
+ languages have. Overloads are difficult and controversial to implement in
+ Rust, so it's unlikely this pattern would be adopted.
+</p>
+
+<h3>Prior art</h3>
+
+<p>
+ Several previous attempts at named arguments, both in Rust and in other
+ languages, have been described throughout this RFC.
+</p>
+
+<p>
+ A previous RFC for named arguments exists for Rust. It was rejected mainly
+ because it did not describe what the future of named arguments would look like
+ with optional arguments. This RFC attempts to address as many future uses of
+ named arguments as possible in order to give a full picture.
+</p>
+<p>
+ A pre-RFC was proposed by forum user Azerupi, but no RFC seemed to come as a
+ result of it. Several complications were pointed out by commenters. This RFC
+ attempts to address syntactic ambiguity, the type system, and opt-in naming.
+</p>
+<p>
+ Another pre-RFC proposed using a more Swift-style syntax, which was avoided in
+ this RFC. The pre-RFC also proposed overloading but not default arguments.
+ Arguably the latter is more important than the former.
+</p>
+<p>
+ As was mentioned before, bon offers a procedural macro for creating builders
+ from functions. The existence of this feature shows that there is a desire for
+ named arguments, that would be better handled as a language feature.
+</p>
+
+<p>
+ Other lanaguages with named arguments have also been discussed. The feature
+ proposed here is similar to named arguments from C# or Kotlin, with the
+ difference being that thhe named arguments are opt-in. The syntaxes used by
+ Dart and Swift have also been discussed. Dart uses the following syntax, which
+ looks closer to destructuring than named arguments.
+</p>
+
+<pre>
+void enableFlags({bool? bold, bool? hidden})
+enableFlags(bold: true)
+</pre>
+
+<p>
+ Swift makes all arguments named by default, allowing authors to opt-out by
+ using an underscore before the variable name. This is impossible to port to
+ Rust without making a breaking change to the language. Various proposals have
+ tried to use slightly different syntaxes, but many of them present syntactic
+ ambiguities.
+</p>
+
+<h3>Unresolved questions</h3>
+
+<ul>
+ <li>Should we require named arguments to be given in position order?</li>
+ <li>Is <code>pub</code> the best keyword, or should a different keyword be used?</li>
+ <li>Should default values be required to always be const?</li>
+</ul>
+
+<h3>Future possibilities</h3>
+
+<h4>Default parameter values for trait methods</h4>
+
+<p>
+ Trait methods were forbidden from having default values due to the question of
+ if the default value should be on the trait declaration or the trait
+ implementation. Having it be on the implementation would be consistent with
+ how associated types and constants work. But this would make it hard for such
+ a trait to be dyn-compatible.
+</p>
+
+<p>
+ One solution would be to only allow default values to be used in non-dyn
+ contexts.
+</p>
+
+<pre>
+trait Foo {
+ fn bar(&self, baz: i32 = 0);
+}
+
+impl Foo for i32 {
+ fn bar(&self, baz: i32 = i32::MAX) {}
+}
+
+fn do_bar&lt;T: Foo>(x: &T) {
+ x.bar(); // baz doesn't need to be specified, since we're using generics
+}
+
+fn do_bar_2(x: &dyn T) {
+ x.bar(); // ERROR: baz must be specified when using a method on a dyn object
+}
+</pre>
+
+<h4>Extending traits</h4>
+
+<p>
+ Theoretically, there's nothing preventing the following, as long as a default
+ parameter value is provided:
+</p>
+
+<pre>
+impl&lt;T> Default for Vec&lt;T> {
+ fn default(capacity: usize = 0) -> Self {
+ Self::with_capacity(capacity)
+ }
+}
+</pre>
+
+<p>
+ Although, in addition to making the behavior of the <code>default</code>
+ function inconsistent, this is even harder to resolve in a <code>dyn</code>
+ context. The likely remedy would be to forbid <code>Vec</code> from being
+ converted into a <code>dyn Default</code>, which would make introducing the
+ named parameter a breaking change.
+</p>
+
+<h4>Requiring named arguments in a future edition</h4>
+
+<p>
+ Allowing named arguments to be optional is necessary in order to backport them
+ into existing functions without creating breaking changes. This comes with
+ some compromises, as has been described in the "Drawbacks" section. However,
+ the way this RFC is drafted makes it possible to require named arguments in a
+ future edition of Rust. Specifying a named argument would not give a warning
+ in either the previous edition or the new edition.
+</p>
+
+<p>
+ Doing this too early would likely hurt adoption of named arguments, as
+ backporting them into existing functions would become a breaking API change.
+ This would also increase the verbosity of calling functions which make use of
+ named parameters, hurting adoption further.
+</p>
+
+<h4>More flexible re-ordering</h4>
+
+<p>
+ As mentioned before, re-ordering of named arguments is allowed by this RFC,
+ in a limited way. The limitations are kept in order to keep the rules easy to
+ explain and reason about. However, some languages allow arguments to be
+ re-ordered more flexibly, and this would be possible to do in the future.
+</p>
+
+<p>
+ C#'s main rule is that out-of-order named arguments cannot be followed by
+ positional arguments.
+</p>
+
+<pre>
+print_order_details(order_num: 31, product_name: "Red Mug", seller_name: "Gift Shop");
+print_order_details(seller_name: "Gift Shop", product_name: "Red Mug", order_num: 31);
+print_order_details("Gift Shop", 31, product_name: "Red Mug");
+print_order_details(seller_name: "Gift Shop", 31, product_name: "Red Mug");
+
+// this would cause an error
+print_order_details(product_name: "Red Mug", 31, "Gift Shop");
+</pre>
+
+<h4>Defaults Affect Inference</h4>
+
+<p>
+ In 2022, Gankra proposed using default parameter values as part of inference
+ for generic type parameters. We could imagine something like this.
+</p>
+
+<pre>
+fn default_hasher() -> RandomState { ... }
+
+impl &lt;K, V, S: BuildHasher> HashMap&lt;K, V, S> {
+ fn new(hasher: S = RandomState::default()) { ... }
+}
+
+// uses S=RandomState
+let map = HashMap::new();
+</pre>
+
+<p>
+ The downside of this particular approach, as Gankra pointed out, is that this
+ would only allow the argument to be omitted if the type of <code>S</code> is
+ <code>RandomState</code>. Although, that's already true with the current set
+ of <code>HashMap</code> factories, unless you use <code>default</code> which
+ doesn't have any parameters at all.
+</p>
+
+<h4>Generic const</h4>
+
+<p>
+ In the case of <code>Vec</code>, adding an optional <code>capacity</code>
+ parameter is not possible with this iteration of the RFC, because
+ <code>Vec::new</code> is a <code>const</code> function, and allocating memory
+ cannot be done at compile-time. This is a very difficult problem to solve,
+ and it's possible that it never will. However, if keyword generics are added
+ to the language, it may be possible to do something like this:
+</p>
+
+<pre>
+const&lt;C> trait Capacity: Copy {
+ const&lt;C> fn allocate&lt;T>(self) -> Option&lt;Box&lt;[MaybeUninit&lt;T>]>>;
+
+ const fn as_usize(self) -> usize;
+}
+
+const impl Capacity for () {
+ const fn allocate&lt;T>(self) -> Option&lt;Box&lt;[MabyUninit&lt;T>]>> {
+ None
+ }
+
+ const fn as_usize(self) -> usize {
+ 0
+ }
+}
+
+impl Capacity for usize {
+ fn allocate&lt;T>(self) -> Option&lt;Box&lt;[MaybeUninit&lt;T>]>> {
+ Some(Box::default())
+ }
+
+ const fn as_usize(self) -> usize {
+ self
+ }
+}
+
+const&lt;C> impl&lt;T, Cap: const&lt;C> Capacity> Vec&lt;T> {
+ pub const&lt;C> fn new(capacity: Cap = ()) -> Self {
+ Self {
+ len: 0,
+ capacity: capacity.as_usize(),
+ buffer: capacity.allocate(),
+ }
+ }
+}
+</pre>
+
+<p>
+ If no argument value is provided, then the function would be
+ <code>const</code>. But when a <code>usize</code> is provided, then it would
+ no longer be <code>const</code>.
+</p>
+
+</article>
+</body>