this post was submitted on 06 Jul 2023
25 points (93.1% liked)

Rust

5658 readers
72 users here now

Welcome to the Rust community! This is a place to discuss about the Rust programming language.

Wormhole

[email protected]

Credits

  • The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)

founded 1 year ago
MODERATORS
top 8 comments
sorted by: hot top controversial new old
[–] [email protected] 26 points 1 year ago (3 children)

But the author doesn't mention the most common way to pass named argument, so I include a comment from mjec over at lobster.rs that covers that (since I'm to lazy to write my own):

It’s not obvious to me why the author didn’t include direct instantiation of the struct, rather than a builder:

#[derive(Default)]
struct SearchOptions {
   pub include_inactive: bool,
   pub age_within: Option<(u32, u32)>,
   // ...
}

let result = search_users(
 users,
 SearchOptions {
   include_inactive: true,
   age_within: Some((5, 29)),
   ..Default::default()
 }
);

This avoids the need for boilerplate enums, or to filter through a vec in order to find the value of an argument. Every caller has to specify ..Default::default() but I don’t mind that! I like the idea that you have to explicitly acknowledge that you want everything else to be default values (and it might be useful to omit it in some places, so you get a compile error if new options are introduced).

[–] [email protected] 10 points 1 year ago

It's honestly strange that this isn't mentioned in the article since it mentions several much worse ways to do it!

[–] [email protected] 6 points 1 year ago

ya, maybe it's the author's ruby background? For example, in languages like go and C, using structs for optional arguments is basically the norm.

[–] taladar 1 points 1 year ago

I would say the main downside of that approach is that it doesn't give you an error for new options in the version that includes Default::default(). There might also be some issues with new options being breaking changes but I am not familiar enough with the rules for that to say.

[–] darcy 14 points 1 year ago (1 children)

seeing hashmaps be used as function arguments in rust is cursed

[–] [email protected] 3 points 1 year ago

Taking the best parts from Perl, hashmaps for everyting ;)

[–] [email protected] 8 points 1 year ago

Another option that the author didn't mention: Newtypes.

There's a pretty neat example for this in Rust By Example: https://doc.rust-lang.org/rust-by-example/generics/new_types.html

If you don't factor out the instantiation of the parameters, you get pretty close to having named parameters, actually:

struct Weeks(u32);
struct Days(u32);

fn add_weeks_to_days(weeks : Weeks, days: Days) -> Days {
    let w = weeks.0;
    let d = days.0;
    Days(7*w+d)
}

fn main(){
    let Days(r) = add_weeks_to_days(Weeks(5), Days(3));
    println!("5 weeks and 3 days equals {r} days.");
}

(Playground)

It is a little bit more work when writing the API, and the caller has to type a tiny bit extra when calling the function, but it also removes all ambiguity regarding the order of the funtion parameters. If also used on the return type, we suddenly get "named" return values too.

[–] [email protected] 4 points 1 year ago

Does anybody have insight into the design choice away from named arguments? Everything in the article and in the comments seems like different levels of kludge around an unfortunate decision