# \[Pre-RFC\] named arguments

**URL:** <https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831>\
**Category:** language design\
**Created:** [August 8, 2016, 9:57am UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831 "2016-08-08T09:57:08Z")\
**Posts on this page:** 20\
**Page:** 15

<div class="post-metadata">

**Author:** ![gbutler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gbutler/32/3670_2.png) [@gbutler](https://internals.rust-lang.org/u/gbutler)\
**Post date:** [May 19, 2019, 12:32pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/284 "2019-05-19T12:32:27Z")

</div>

> > Keyword names are set in stone, even if newer versions of a library would like to make even backwards-compatible changes.

Personally, I find this argument entirely unconvincing. The same could be said about method names or any other names in the API. Why should field names be any different. How often (really?) would you need or want to change the field names in a stable API? I think this sort of objection is finding a problem that doesn't exist in reality. YMMV.

---

<div class="post-metadata">

**Author:** ![samsieber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/samsieber/32/4671_2.png) [@samsieber](https://internals.rust-lang.org/u/samsieber)\
**Post date:** [May 19, 2019, 2:45pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/285 "2019-05-19T14:45:19Z")

</div>

Correct me if I am wrong, but it seems the issue mentioned/addressed in pythom was that positional arguments were callable through named argument syntax. That’s very much a footgun as I expect that library maintainers often didn’t realize that the name of positional parameters were part of their public API.

I think making named parameters opt in solves it neatly enough. And other things, like adding internal vs public names gives further protection.

I can see people changing argument names during refactoring or bug fixing.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [May 19, 2019, 4:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/286 "2019-05-19T16:30:42Z")

</div>

> [@gbutler](#):
>
> How often (really?) would you need or want to change the field names in a stable API?

Well you obviously never _need_ to, in the same way that it's valid to just name everything with guids.

But the names show in documentation, in assert messages, etc, so here's an example where I renamed one:

> <https://github.com/rust-lang/rust/pull/56425/files>
>
> Inspired by the \[recent conversation on IRLO\](https://internals.rust-lang.org/t/…make-vec-set-len-enforce-the-len-cap-invariant/8927/23?u=scottmcm).
> 
> This is just my first stab at this; suggestions welcome.

That's also a case where I struggle to understand why anyone would _want_ to name the parameter in the call site.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 3, 2019, 10:13pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/288 "2019-07-03T22:13:33Z")

</div>

> [@anon2808951](#):
>
> without further increasing the footprint of the language

It seems like the footprint increase of this is at least as large as saying that a `foo` parameter _isn't_ publicly-named but a `@foo` parameter (or `pub foo` or whatever) _is_ publicly-named.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [July 6, 2019, 12:32pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/289 "2019-07-06T12:32:32Z")

</div>

How about:

- arguments are always positional
- all arguments have always to be supplied
- arguments have to come in the correct order

but

- a name may _optionally_ be supplied with an argument
- it is then a compilation error not to match argument name in function definition/declaration
- if a trait and its `impl` use different names for the same argument some rules decide which is “more visible” at the call site

Here argument names serve to prevent confusion and improve readability. Argument names are not part of the function type and are obliterated in `Fn` traits. Possibly `Fn` traits are assumed to have non-descriptive argument names like `a0, a1, a2..`

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [July 6, 2019, 5:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/290 "2019-07-06T17:03:22Z")

</div>

> [@atagunov](#):
>
> if a trait and its `impl` use different names for the same argument some rules decide which is “more visible” at the call site

That sounds like a recipe for disaster. If mismatching argument names in other places is disallowed, why should it be allowed between the declaration and the impl of a trait method?

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [July 6, 2019, 10:28pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/291 "2019-07-06T22:28:43Z")

</div>

> [@H2CO3](#):
>
> That sounds like a recipe for disaster. If mismatching argument names in other places is disallowed, why should it be allowed between the declaration and the impl of a trait method?

Hi H2CO3, so you like the idea otherwise? 🙂 I just wanted to make sure we're on the same page

```rust
fn foo(arg: i32) {...}
foo(42); // ok
foo(arg : 42); // ok
foo(anotherName : 42); // compilation error

trait Xyz { fn bar(&self, arg: i32); }
impl Xyz for i32 { fn bar(&self, superArg: i32) {...} } // compiles now
                         // so we can't possibly declare this an error?

14.bar(42); // ok
14.bar(arg : 42); 14.bar(superArg : 42); // one of these should be ok
                               // and the other should be an error, right?
                               // since this is a new feature we probably can
                               // define a rule to our liking which one is which?
```

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [July 7, 2019, 6:02am UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/292 "2019-07-07T06:02:27Z")

</div>

I was only reacting to this particular aspect of the suggestion.

Otherwise, I’m not keen on named arguments at all. In my experience they are a massive pain in the neck in a statically-typed language, especially in the context of a dynamically-called function (e.g. `fn` pointer or a closure). There, various rules need to be bent in some way, in order to allow either functions with named arguments to be called without names, or vice versa, or to make argument names part of the function type, which has its own set of problems and inconveniences.

For my taste, the order of 2 arguments is easy to remember **and** they can be easily differentiated via newtypes anyway. 3 arguments is already too much and should be refactored with a `struct` having proper named fields. The currently-stale structural records proposal would make this even more convenient without the need of having to define a named struct in these cases, but it’s a neat solution even without anonymous structs.

---

<div class="post-metadata">

**Author:** ![pythoneer](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pythoneer/32/2010_2.png) [@pythoneer](https://internals.rust-lang.org/u/pythoneer)\
**Post date:** [July 7, 2019, 6:15am UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/293 "2019-07-07T06:15:38Z")

</div>

> [@H2CO3](#):
>
> The currently-stale structural records proposal would make this even more convenient without the need of having to define a named struct in these cases, but it’s a neat solution even without anonymous structs.

I highly agree on this. structural records would eliminate most of the problems i can agree on for "missing" named arguments – they're neat in some niche "genre" of programming at least for my taste, but i really don't need them. Its nice to have in 3D programming (that's just my personal taste) but i don't miss them in any other aspect i use Rust for.

Just for other people entering the conversation [here is the rfc for structural records](https://github.com/rust-lang/rfcs/pull/2584) (i hope that's the one you're referring to)

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [July 7, 2019, 11:32am UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/294 "2019-07-07T11:32:37Z")

</div>

> [@H2CO3](#):
>
> 3 arguments is already too much and should be refactored with a `struct` having proper named fields.

Would it alternatively be possible to make this case easier by allowing the type of a struct be omitted but not adopting structural record types? This would avoid extending the type system but make calling methods with a struct arguments for the sake of naming its arguments somewhat easier.

```rust
struct Dog { … }

impl Dog {
    pub fn woof(&self, woof: Woof) -> Sound;
}

/// Only exists to provide names to `woof` arguments
struct Woof {
    pitch: f32,
    loudness: f32,
    repeats: u32,
}

good_boy
    // Type is uniquely deductible. Being able to omit it here also
    // means we don't need to `use` it.
    .woof(_ {
        repeats: 5,
        pitch: 440.,
        loudness: 80.,
    })

```

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 7, 2019, 7:18pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/295 "2019-07-07T19:18:53Z")

</div>

> [@197g](#):
>
> allowing the type of a struct be omitted but not adopting structural record types?

Yes, I think this (possibly combined with _anonymous_ struct types) would be better than structural records.

This came up in

> [@Idea: reducing boilerplate in APIs that use ADTs](https://internals.rust-lang.org/t/idea-reducing-boilerplate-in-apis-that-use-adts/4889):
>
> Rust doesn’t have named/keyword arguments yet, and there has already been several RFCs and discussions about it over hundreds of posts long. I admit I did not read most of that, so if I’m just repeating what had already been said, feel free to point me to the relevant discussions. Motivation The core idea is that I think Rust’s structs and enums are already quite good for expressing APIs, if only they could be a little more ergonomic (less boilerplate). Consider, for example, an API like this…

---

<div class="post-metadata">

**Author:** ![paddyg](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/paddyg/32/5900_2.png) [@paddyg](https://internals.rust-lang.org/u/paddyg)\
**Post date:** [July 25, 2019, 10:37am UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/296 "2019-07-25T10:37:20Z")

</div>

Quite a good approach IMHO is to _not change anything_ but use meaningful names for variables and put argument names in comments if needed. i.e.

```
let mut disp = Display::new(X, Y, W, H, /*obscure_param*/ 666.999);
        disp.set_background(/*r,g,b,a*/ &[0.1, 0.1, 0.2, 1.0]);
        disp.set_title("Example Window");
        disp.set_target_fps(24.0);

let label = String::new(&font, "Hello World", /*justify*/ 0.0);

```

an advantage of this approach is that the `/*name*/` in the fn argument call could be _more_ meaningful than just the actual name.

Also this DIY builder approach makes it clear that the Display instance is now mut. If that's not wanted then there would be a clear line following it..

```
    ...
            disp.set_target_fps(24.0);
    let disp = disp; // i.e. no longer mut

```

Note that it doesn't actually use more lines than the _chaining dots_ system, with the advantage that you don't have to look at the source code for Display to figure out what's happening.

---

<div class="post-metadata">

**Author:** ![asa-z](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/asa-z/32/6771_2.png) [@asa-z](https://internals.rust-lang.org/u/asa-z)\
**Post date:** [July 25, 2019, 4:48pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/297 "2019-07-25T16:48:41Z")

</div>

What if argument labels were part of the name of the function? This would make them mandatory, and also allow using them to differentiate functions.

```rust
impl Rectangle{
  pub fn new(width:f64, height:f64)->Rectangle{...}
  pub fn new(area area: f64, width width: f64)->Rectangle{...}
}

let r1 = Rectangle::new(3.0,4.0);
let r2 = Rectangle::new(area:12.0, width: 3.0);

```

This is not overloading, because the name of the second function is `new(area:width:)`, while the first is `new`, and to get a reference to the second, you would have to use `Rectangle::new(area:width:)`, while for the first, `Rectangle::new`. Also, syntax for the same inner and outer names could be improved. Also, the inner and outer names of the functions can be different, as the best internal names of arguments are not always the best at the callsite.

This would turn using named arguments into an api design decision, and would be opt in, so no backwards compatibility issues.

---

<div class="post-metadata">

**Author:** ![Dante-Broggi](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dante-broggi/32/5798_2.png) [@Dante-Broggi](https://internals.rust-lang.org/u/Dante-Broggi)\
**Post date:** [July 25, 2019, 5:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/298 "2019-07-25T17:33:13Z")

</div>

> [@asa-z](#):
>
> What if argument labels were part of the name of the function? This would make them mandatory, and also allow using them to differentiate functions.

This is how Swift does it, modulo some source compatibility problems from when parameter labels were part of the type, not the name, discussed [here](https://forums.swift.org/t/require-parameter-names-when-referencing-to-functions/27048).

(Namely, that any function can be referenced, when not called directly, by its 'base name', e.g. without argument names.)

---

<div class="post-metadata">

**Author:** ![asa-z](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/asa-z/32/6771_2.png) [@asa-z](https://internals.rust-lang.org/u/asa-z)\
**Post date:** [July 25, 2019, 5:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/299 "2019-07-25T17:36:54Z")

</div>

Yes. However Swift has overloading, so it's a little more complicated, and also, the syntax is a bit better because it was designed from the beginning. Also, swift's apis have been designed with this in mind, so `size_of` in rust would be `size(of:)` in swift. As Rust's style has already sort of solidified, it would feel a little different.

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [October 9, 2019, 12:47am UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/300 "2019-10-09T00:47:34Z")

</div>

I really believe that Rust should get named arguments eventually. And it's not about convenience or being more friendly to people coming from dynamic languages, but about helping to prevent bugs and thus making software more reliable (i.e. to be closer to Ada, not Python). And I did encounter bugs which could've been solved by named arguments, for example [`flat_projection`](https://docs.rs/flat_projection/) uses lon/lat order instead of a more common lat/lon order (motivation being that lon/lat mirrors X/Y), which I've used automatically out of habit. It took a fair amount of time to find the reason why my program was misbehaving. In RustCrypto we also have encountered this problem when designing [AEAD](https://en.wikipedia.org/wiki/Authenticated_encryption#Authenticated_encryption_with_associated_data_(AEAD)) traits. Initially we have used `cipher.encrypt(nonce, plaintext, ad)`, but since authenticated data and plaintext both have type `&[u8]`, there was a real danger that users will use the wrong order, which may have serious implications. We "solved" it with an additional `Payload` type, enhanced with [a cute trick](https://github.com/RustCrypto/traits/pull/48) to improve ergonomics.

I've read most of this thread and I think I have a variant which was not proposed yet.

Initially I was in favor of somehow utilizing the struct symmetry for named arguments, but after a fair amount of thinking I've come to a conclusion that it's probably a dead end. There is simply too many issues with generic code and conflicts with type ascription, and attempting to solve them will make feature too big and scary to accept.

Instead I would like to suggest "pub argument blocks" (PAB):

```rust
fn foo(a: u32, pub { b: u32, c: u32 }) { .. }
fn bar(pub { a: u32, b: u32 }) { .. }
fn baz(a: u32, pub { b: u32 = 1, c: u32 = SOME_CONST }) { .. }

const fn f() -> u32 { .. }
fn zoo(&self, pub { a: u32 = f()}) { .. }

// foo has type Fn(u32, u32, u32), so
foo(1, 10, 30);
// is equivalent to
foo(1, b = 10, c = 30);
// with type ascriptions
foo(a: u32, c = 1: u32, b = my_b: u32);
// arguments with a default value can be omitted
baz(1);
baz(1, c = 10);
z.zoo();

```

Why introduce the block instead of using `pub` before the each argument? First, it's less duplication, and second it will highlight that PAB has some additional constraints and capabilities.

Allowing positional usage of named arguments will allow to add them into existing codebases in a backward compatible fashion (ofc with a MSRV bump). Plus it will limit the scope of the proposal, since for type system function will look as a plain old `Fn(u32, u32, u32)`, without any named type arguments or complications arising from anonymous structs.

PAB will be the only place inside of which default values for arguments will be allowed. Note that only constants can be used as default values. Some may argue that it may be useful to be able to call any function for initializing a default value during runtime (e.g. to allocate some space on the heap for a value), but I think it's a needless complication which does not pull it's weight, plus it may be unintuitive, since AFAIK other languages do not allow such functionality.

PAB will be different from the usual arguments, you will not be able to use patterns, only identifiers, i.e. the following code will be illegal:

```rust
fn foo(pub { (a, b): (u8, u32) }) { .. }

```

Of course positional arguments can not be defined or used after named arguments:

```rust
// both lines will cause a compilation error
fn f(pub {a: u32}, b: u32) { .. }
foo(b = 10, c = 30, 1);

```

Now about the calling syntax, as was mentioned many times in this thread, this code is legal right now:

```rust
let mut a = 0;
f(a = 1); // `a = 1` evaluates to `()`

```

I think it should be possible to solve this issue in the next edition (either way, I don't think "named arguments" have a chance to be stabilized before the next edition). In other words, in the next edition inside function call parser will prioritize parsing `<ident> = <expr>` over parsing expression, while for 2015/2018 edition crates it will work as it does currently.

If for some reason it will not be possible to do it, then there are a bit more ugly options like `:=`. But I really hope we will be able to use `=`.

Why not try to work around parsing issues for `:` instead of `=`? Since PAB do not use any symmetry with structs, I don't think we should use `:` for named arguments and in context of function calls leave it for type ascription only.

In future we may even somehow extend PAB with variadic arguments.

Because PAB do allow positional usage of named arguments, some may say that this proposal does not help with bug prevention, since lazy users will omit argument names or they may delete them (which may cause [lat/lon issues](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/148) raised by @graydon). I think a good way to solve this issue will be to mirror `#[must_use]` and introduce an attribute, which will emit warning if named arguments are used in positional form:

```rust
fn foo(pub { lat: f32, lon: f32}) { .. }
#[check_pub_args]
fn bar(pub { lat: f32, lon: f32}) { .. }

// no warnings
foo(1.0, 2.0);
bar(lat: 0.0, lon: 0.0);
// warning: use function argument names
bar(0.0, 0.0);
// for convenience sake we probably should omit warning
// if variable names match argument names, i.e.
// this line will not result in a warning
bar(lat, lon);
// but this one will emit a warning
bar(lon, lat);

```

Sorry for a relatively rough description of the PAB idea, but I hope was able to explain it well enough for you to understand the general idea and its properties. I think PAB with the attribute solves most of the issues raised in this thread, ergonomic to use and has a very limited scope, which should prevent weird corner cases when used in combination with other Rust features.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [October 9, 2019, 10:52am UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/301 "2019-10-09T10:52:46Z")

</div>

@newpavlov: 👍 ... -`defaults` +`mandatory order` = an even simpler design

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [October 9, 2019, 2:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/302 "2019-10-09T14:23:35Z")

</div>

> [@newpavlov](#):
>
> Because PAB do allow positional usage of named arguments, some may say that this proposal does not help with bug prevention, since lazy users will omit argument names or they may delete them (which may cause [lat/lon issues](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/148) raised by @graydon). I think a good way to solve this issue will be to mirror `#[must_use]` and introduce an attribute, which will emit warning if named arguments are used in positional form:

Personally I'd prefer the opposite: require named arguments, for the precise reason to remove ambiguities as a safe(r) default.

For those cases where you require it for backwards-compatibility, or if you simply want default parameter values, add an attribute `#[allow_positional]`

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/newpavlov/32/3290_2.png) [@newpavlov](https://internals.rust-lang.org/u/newpavlov)\
**Post date:** [October 9, 2019, 3:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/303 "2019-10-09T15:59:22Z")

</div>

> [@lordan](#):
>
> Personally I'd prefer the opposite: require named arguments, for the precise reason to remove ambiguities as a safe(r) default.

Hm, your approach may be indeed a better solution considering Rust's spirit. But note, that I propose to issue only warnings, not compilation errors, so you will not need `#[allow_positional]` for backwards compatibility. Of course it could be a compilation error instead, but I don't think it's worth the churn.

---

<div class="post-metadata">

**Author:** ![Keats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/keats/32/1715_2.png) [@Keats](https://internals.rust-lang.org/u/Keats)\
**Post date:** [October 9, 2019, 8:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831/304 "2019-10-09T20:41:39Z")

</div>

A huge 👍 for this proposal, although as mentioned already I would prefer if the arguments have to be named by default, and with an `#[allow_unnamed_args]`.

[Previous page](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831.md?page=14)

[Next page](https://internals.rust-lang.org/t/pre-rfc-named-arguments/3831.md?page=16)
