Rust dev argues structs beat named arguments for API design
An engineer contends Rust's type system already provides better solutions to function parameter problems than adding named arguments would.
What to know
- Rust can achieve the practical benefits of named/optional/default arguments using structs and its existing type system, without adding language features or complexity.
- The struct-based approach forces API designers to recognize when parameters form a semantic unit, leading to better abstraction and reusable configuration objects.
- Critics argue the struct syntax introduces significant boilerplate and that modern IDEs already surface parameter names, eliminating the friction argument for API discipline.
- A Rust team member indicated default field values are being stabilized, suggesting incremental improvements to the struct workaround are in progress.
The dispute Whether the friction of struct-based function parameters is a beneficial constraint that improves API design (author's view) or an unnecessary burden that modern tooling has already made irrelevant (critics' view). · positions read across 31 posts and comments
Friction from struct syntax is a feature: it forces developers to recognize semantic groupings and design better APIs.
-
“After seeing the implications of making parameter names part of the public API, I don't think the complexity of expressing that is worth it.”
ancienthero · Lobsters ↗
Struct boilerplate is excessive and unjustified; IDEs eliminate the friction argument, making named parameters straightforwardly better.
-
“This is supposed to be good code?? I don't see how people can look at struct constructors and think…”
spillybones · Lobsters ↗
Syntax improvements (inferred struct names, mixed required/optional fields, default field values) could make structs ergonomic without full named parameter complexity.
-
“I wish Rust had Zig's inferred struct name…becomes just _ { x: 10, y: 20, width: 200, height: 100, }”
yshui · Lobsters ↗
itamarst Rust developer / authorSteve Klabnik Rust contributor (referenced)ekuber Rust team member
How it unfolded 6 developments, newest first · click a bar or a number to jump postscomments
-
6
Some commenters persuaded by reusability argument
Counterargument emerges: using structs allows configuration to be passed and reused across multiple function calls, offering flexibility that pure named arguments wouldn't provide. This benefit shifts some readers' views on the tradeoff.
“Having that as a struct makes it trivial to do so, while arguments would force you to either make your own…”
— gavinmorrow -
I wish you could do this with enums. I really love how in Swift, you can do stuff like `let color = .red`. It would be nice to be able to do `let color = _::Red;` in Rust.
2 more of the top 3 · 3 posts in this stretch
-
I had previously been in favor of named arguments, but I think this convinces me. Once you add keyword arguments, you have to add a whole host of other features *that already exist*, just for structs instead of functions. The other benefit of using a struct when there are so many parameters is that you can now pass around that configuration in…
-
If you were to have default field values and elided struct names, you could instead have this. While it is still more verbose, it does become much more reasonable. (Even if you didn't have elided struct names, it wouldn't be too bad.) You can also then pass around `RequestOptions` in other code as you like, for example if you have a bunch of calls…
-
-
5
Critics highlight practical verbosity costs of struct approach
Commenters push back on the essay's claim that struct-based parameters are reasonable, showing that the boilerplate—defining structs, implementing Default, using spread syntax—is significantly more verbose than simple named parameter syntax. One commenter questions whether the approach is actually good code.
“This is supposed to be good code?? I don't see how people can look at struct constructors and think…”
— spillybones -
OP says instead of this, ``` request(url, follow_redirects: false); ``` all you have to do is this: ``` struct RequestOptions { timeout: Duration, follow_redirects: bool, } impl Default for RequestOptions { fn default() -> Self { Self { timeout: Duration::from_secs(30), follow_redirects: true, } } } request( url, RequestOptions { follow_redirects…
2 more of the top 3 · 8 posts in this stretch
-
A lot of cope. Reads like the sort of article the Go community would write... Speaking as someone that loves Go. The point of optional arguments is that a predetermined default value is used if nothing is passed, passing `none` is not the same as passing nothing since none is a value in languages like Rust and Python. Using structs for keyword…
-
I don't see the difference with the RFC feature. The fact that yours doesn't `derive(Default)`? I don't _think_ that's required for `default_field_values` either (but the examples make it ambiguous).
-
-
4
Commenters propose syntax improvements to reduce struct boilerplate
Multiple commenters suggest language features that could make the struct-based approach less verbose: Zig-style inferred struct names (underscore placeholders), mixed required/optional fields via a PartialDefault trait, and enum type inference. These proposals indicate dissatisfaction with the verbosity of the current workaround.
“I wish Rust had Zig's inferred struct name…becomes just _ { x: 10, y: 20, … }…”
— yshui -
https://doc.rust-lang.org/unstable-book/language-features/default-field-values.html I plan on stabilizing that before the end of the year. There's only one blocker around semantics and it is being actively worked on.
2 more of the top 3 · 5 posts in this stretch
-
> you can't seriously say this about Rust, a very complex language; the extra complexity isn't much compared to what's already in there. Keeping an eye on the complexity budget to stave off becoming the next C++ "just one more little thing" at a time has been deep in Rust's RFC process since the beginning. Hell, Rust RFCs were I learned the…
-
I wish Rust had Zig's inferred struct name. i.e. this: ```rust let cropped = image::imageops::crop_imm( &img, Crop { x: 10, y: 20, width: 200, height: 100, }, ); ``` becomes ```rust let cropped = image::imageops::crop_imm( &img, _ { x: 10, y: 20, width: 200, height: 100, }, ); ```
-
-
3
Rust team member signals work on default field values feature
An ekuber, identified as a Rust contributor, comments that default field values are being stabilized and should ship before year-end, with only one semantic blocker being actively worked on. This development suggests the language may address one of the workarounds discussed in the essay.
“I plan on stabilizing that before the end of the year. There's only one blocker around semantics and it is being actively worked on.”
— ekuber -
Back when I was first implementing restructuring assignment in JavaScript I realised that it made named arguments* really nice: function f({x, y, z}) { … } That said I’m not super keen on the struct based approach in strongly typed language as it means _every_ function starts needing its own type specified. I don’t think the argument that the type…
2 more of the top 3 · 9 posts in this stretch
-
My IDE that shows me parameter names at any call site. Whatever "friction" the author is depending on to enforce their idea of good taste isn't there with the right tooling. It would still be nice if Rust directly supported named parameters. In both posts, it also seems assumed that if Rust gets named parameters then argument defaults and function…
-
Right - the examples in the article (things like Size, etc) are reasonable, but in many cases that's not what you have so you litter your API surface with myriad single use structs. The more I think about it, the more I realize is that the problem is the labeled parameters are seen as a property the parameter, rather than as part of the _function…
-
-
2
Community members respond with mix of agreement and skepticism
Lobsters commenters debate the essay's merits. Some agree that friction in function calls drives better API design; others argue the struct-based workaround adds boilerplate, that IDEs eliminate the friction argument, and that Rust could support named parameters without forcing optional arguments or overloading.
“After seeing the implications of making parameter names part of the public API, I don't think the complexity of expressing that is worth it.”
— ancienthero -
What a nicely written article > friction produces better APIs Couldn’t agree more! I’m all for languages having a smaller set of features rather than being ever-growing
2 more of the top 3 · 6 posts in this stretch
-
I used to be in the camp for keyword/optional arguments, but thinking about it more I've changed my mind completely. After seeing the implications of making parameter names part of the public API, I don't think the complexity of expressing that is worth it. Not to mention, the default values of optional arguments are also practically part of the…
-
"All of the above might be useful, though localized, syntax improvements. But the hidden tax is that the language becomes more complex, for arguably little gain." -- you can't seriously say this about Rust, a very complex language; the extra complexity isn't much compared to what's already in there. The gain is IMO very real - you get a nice API…
-
-
1
Developer publishes essay defending Rust's struct-based approach to function parameters
An author responding to Steve Klabnik's earlier piece on named arguments publishes "We Have Named Arguments at Home," arguing that Rust can achieve 80% of the ergonomics of named, optional, and default arguments without adding language features. The essay contends that using structs as argument bundles is superior because it makes parameter groupings semantically meaningful and avoids hidden calling convention complexity.
“I actually think we can get most of what we want without adding any new language features. Instead, we can lean into what Rust already provides.”
— itamarst
What people are saying 9 voices from 1 site · best of 31 · verbatim
- Could Rust add named parameters without also requiring optional arguments and overloading, as some commenters suggest?
- Would default field values (the stabilization in progress) be sufficient to address the ergonomic gap, or are further syntax features needed?
- Does the reusability benefit of configuration structs justify the boilerplate cost compared to named parameters in practice?
- Yesterday
-
Yeah, I think their point about friction when writing making you think less applies more to the code in their AI generated article than to single function calls.
-
Lots of things don't work with `impl Trait` arguments. `arg as _`, `arg.into()`, sometimes even `&arg` when you get `&T` instead of `T`'s `Deref` or `&dyn`
-
My man! Not 100% what I was thinking, but this is great. For my use case I'm thinking something like this: ``` #[PartialDefault] struct Contact { #[required] address: Address, #[optional] favorite_color: Option } ``` Then someone could: ``` Contact { address: &home, ..PartialDefault::default } ``` But this would not be allowed to `Contact {…
-
> An optional argument is, to some extent, an argument which may or may not exist. Rust has a type for that. A thing I’m missing is to have a mix of required and optional fields in a struct. When you mark it Default ALL fields must provide a default and that also makes those types less useful (fewer guarantees). Or you end up having to wrap things…
-
I've written something similar years ago
-
I do many/most of these things all the time. Is that not normal? Actually, when I first opened Steve’s article I expected it to read more like this one!
-
I broadly agree with this (especially considering the conclusion that thinking about restructuring the API is better than poorly emulating these features in the first place) although it somewhat feels like making excuses for "why this design you don't like and can demonstrably be done more conveniently is good actually". But like a lot of…
-
I don't follow. Why do you think this friction will lead to bad APIs?
-
I tend to agree with this. Most of it applies to Go too, except for the part about default structs. It adds friction, but in a static language a little bit of friction can be good.