Live data from Hacker News

Builder Pattern in Rust

greyblake.com

71–80 of 93 posts

Re: Builder Pattern in Rust

#72
post #15

> Since we do not have default arguments in Rust, in order to initialize such structure we would have to list all fields: I'm surprised the article doesn't mention Default: https://doc.rust-lang.org/std/default/trait.Default.html It can be combined with the rest pattern to yield something very similar to the solution the author is after. https://stackoverflow.com/questions/19650265/is-there-a-fast...

What bugs me a bit about Rust is the lack of default parameters. Even with the Default trait, the caller still has to write a bit of boilerplate ( ..Default::default()). The caller needs to know that the input struct implements Default. And you would need one input struct per function (if default values differ). Are there better ways or is it planned to introduce something like default parameters?

Default parameters, optional parameters, and named parameters kind of form this massive design space where they all sorta kinda influence each other, and so while there hasn't been a formal "yes" or "no" directly from the team about these features, they tend to get caught up in a combination of "there are bigger issues to worry about" along with the combinatorial explosion of truly exploring the design space, at least from what I've observed over the years.

Re: Builder Pattern in Rust

#74
post #41

Personally I think if you need a builder, you did something wrong in the first place. If you have a struct with so many defaultable values, you should break it into smaller pieces. Reasonable struct should not need more than 5 properties, unless it's something like ORM mapping of database table.

I don't know where you pulled that 5 number from but it seems to come out of thin air.

Besides, breaking structures in smaller structures this way can lead to code that's much harder to follow, refactor, and maintain.

Re: Builder Pattern in Rust

#75
post #45

Earlier quoted context omitted.

The trick is that an empty string doesn’t actually own any data on the heap. It’s basically a null pointer, and all string methods check for that in some way. This is a typical optimization trick that many languages implement (empty lists and strings are very common). Defining new to be const just makes this optimization a requirement.

But still- at a language semantics level, values can't have multiple owners, and String couldn't implement Copy just for this one case. So how does this reconcile with the borrow-checker? Or can consts have multiple owners since they're immutable and have a static lifetime? Is this just the first case of a non-Copy being const, so the question has never come up before?

Ah, I get your question now, I thought you were talking about const functions. Well, const values in Rust are funny things, they're not linked into the executable, they don't have an address or a lifetime. That confused me too for a while. They're purely a shortcut for a value expression, not that different from a #define in C.

Statics, in contrast, have a storage location and a static lifetime.

Compare:

  const CONST_STRING: String = String::new();
  static STATIC_STRING: String = String::new();

  fn main() {
      let x: String = CONST_STRING;  // fine
      let y: String = STATIC_STRING; // error: cannot move out of static item
  }

Re: Builder Pattern in Rust

#76
post #75

Earlier quoted context omitted.

But still- at a language semantics level, values can't have multiple owners, and String couldn't implement Copy just for this one case. So how does this reconcile with the borrow-checker? Or can consts have multiple owners since they're immutable and have a static lifetime? Is this just the first case of a non-Copy being const, so the question has never come up before?

Ah, I get your question now, I thought you were talking about const functions. Well, const values in Rust are funny things, they're not linked into the executable, they don't have an address or a lifetime. That confused me too for a while. They're purely a shortcut for a value expression, not that different from a #define in C. Statics, in contrast, have a storage location and a static lifetime. Compare: const CONST_…

Oh. I think I didn't realize both existed; I'd only used statics before (and knew about const functions), but didn't know about const expressions.

Re: Builder Pattern in Rust

#77
post #35

Earlier quoted context omitted.

This solution works sometimes, but it's not great if any of the fields don't have a sensible default.

You end up having to do struct Parameters { non_optional_parameter_1: Foo, non_optional_parameter_2: Bar, extra_options: ParametersWithDefault, } #[derive(Default)] struct ParametersWithDefault { ... } which is kind of annoying but not the end of the world.

It's a lot of small papercuts, but

    use module::{ foo, Parameters, ParametersWithDefault };

    fn bar() {
        foo(Parameters {
           non_optional_parameter_1: Foo,
           non_optional_parameter_2: Bar,
           extra_options: ParametersWithDefault {
               optional_param: Baz,
               ...Default::default(),
           }
        });
    }
is a far cry in ergonomics from:

    use module::foo;

    fn bar() {
        foo(_ {
            non_optional_parameter_1: Foo,
            non_optional_parameter_2: Bar,
            optional_param: Baz,
            ..
        });
    }
Even just having to import the extra structs (and lookup the names) is a massive pain. Especially if you need to change to use a slightly different function.

Re: Builder Pattern in Rust

#78

Earlier quoted context omitted.

What bugs me a bit about Rust is the lack of default parameters. Even with the Default trait, the caller still has to write a bit of boilerplate ( ..Default::default()). The caller needs to know that the input struct implements Default. And you would need one input struct per function (if default values differ). Are there better ways or is it planned to introduce something like default parameters?

Default parameters, optional parameters, and named parameters kind of form this massive design space where they all sorta kinda influence each other, and so while there hasn't been a formal "yes" or "no" directly from the team about these features, they tend to get caught up in a combination of "there are bigger issues to worry about" along with the combinatorial explosion of truly exploring the design space, at leas…

Thanks for the insight, Steve! I'm glad the team thinks about these issues.

Re: Builder Pattern in Rust

#79
post #38

Earlier quoted context omitted.

What bugs me a bit about Rust is the lack of default parameters. Even with the Default trait, the caller still has to write a bit of boilerplate ( ..Default::default()). The caller needs to know that the input struct implements Default. And you would need one input struct per function (if default values differ). Are there better ways or is it planned to introduce something like default parameters?

> Are there better ways It's a question of taste, but the builder pattern can be considered a “better way”, because of how clunky the use of Default can be. You would prefer an API with easier to read, documented builders than the ..Default::default() call.

What I dislike about the builder pattern is that it treats input not as one 'blob' of data and thus makes simple things more complicated.

Re: Builder Pattern in Rust

#80
post #66

In a relevant sense, common occurrence of a pattern reveals a weakness in the language where it appears, because no one has succeeded in capturing it in a library so it doesn't need to be coded again. Thus, C programs are shot through with hash table implementations, because a generally usable hash table library is not possible in C. Rust has a good one in the standard library, so Rust programs with a custom hash tab…

"Design patterns are bug reports against your programming language." - Peter Norvig

what's wrong with C that you cannot design a general-purpose hash table? Is it that you cannot define a general-purpose function to hash an object and check for equality?

Post reply on HN