Live data from Hacker News

Builder Pattern in Rust

greyblake.com

21–30 of 93 posts

Re: Builder Pattern in Rust

#22
post #7
post #2

I appreciate the tradeoffs that led to the builder pattern becoming commonplace, but it's probably my least favorite part of Rust. Compared to optional named parameters it just feels clunky, verbose and kind of Java-esque.

IMO, the toy example in the article is too simple to show a good use of the pattern. The builder pattern is great if the builder methods configure complicated invariants and are not just setters. Otherwise, there's nothing wrong with making the struct public, as in User { id, email, ..Default::default() } What's Java-esque is having an irrational fear of using public fields for things that are just data containers, b…

[deleted]

Re: Builder Pattern in Rust

#23
post #7

Earlier quoted context omitted.

IMO, the toy example in the article is too simple to show a good use of the pattern. The builder pattern is great if the builder methods configure complicated invariants and are not just setters. Otherwise, there's nothing wrong with making the struct public, as in User { id, email, ..Default::default() } What's Java-esque is having an irrational fear of using public fields for things that are just data containers, b…

This pattern is fairly good but doesn't support required arguments.

You can mix-and-match, e.g.

  new(required_arg_1, required_arg_2, Options { foo: "bar", ..Default::default() })
or

  Options { foo: "bar", ..Default::default() }).build(required_arg_1, required_arg_2)

Re: Builder Pattern in Rust

#24
post #4
post #2

I appreciate the tradeoffs that led to the builder pattern becoming commonplace, but it's probably my least favorite part of Rust. Compared to optional named parameters it just feels clunky, verbose and kind of Java-esque.

I agree. I’ve seen a few libraries (I can’t remember which) instead take the approach of a constructor that takes a single-use struct as an argument. The struct implements Default and all of its members are public. You can then use ..Struct::default() to splice in the default values, and override only the values you want to set. It ends up being an approximation of named optional arguments, albeit with a somewhat mor…

Yeah, I've seen it called the Init Struct pattern: https://xaeroxe.github.io/init-struct-pattern/

Re: Builder Pattern in Rust

#25
post #7

Earlier quoted context omitted.

IMO, the toy example in the article is too simple to show a good use of the pattern. The builder pattern is great if the builder methods configure complicated invariants and are not just setters. Otherwise, there's nothing wrong with making the struct public, as in User { id, email, ..Default::default() } What's Java-esque is having an irrational fear of using public fields for things that are just data containers, b…

This pattern is fairly good but doesn't support required arguments.

I haven't filed an RFC yet, but I have a plan that I'm optimistic can land sometime that would let you write:

  struct User {
    id: Id,
    email: EMail,
    name: String = String::new(),
    age: u16 = 0,
  }
  
  let user = User { id, email, .. }; // valid
  let user = User { id, .. }; // complain about email missing
It would leverage `const` expressions, so it would desugar effectively to the same as if you had written:

  const DEFAULT_USER_NAME: String = String::new();
  const DEFAULT_USER_AGE: u16 = 0;

  struct User {
    id: Id,
    email: EMail,
    name: String,
    age: u16,
  }
  
  let user = User { id, email, name: DEFAULT_USER_NAME, age: DEFAULT_USER_AGE };
The above assumes that String::new will be const at some point (it can be).

If this ever lands, then there will be less need to write Builder traits by hand.

Also, at some point the free-standing `default()` function that calls `Default::default()` will land, making it that much shorter to write (without any new features like I'm proposing).

Re: Builder Pattern in Rust

#26
post #12

Earlier quoted context omitted.

I would quite like to see some syntax sugar around this. If we could elide the type and made `...` equivalent to `..Default::default()` it would be a lot closer to kwargs without having to introduce any new "real" features. So we could write: f(arg1, arg2, _ {name: "Hello", address, ...}) instead of f(arg1, arg2, MyKwargs {name: "Hello", address, ..Default::default()} Using a struct for this feels natural as you get…

I would like this plus the ability to specify per-field defaults on structs like struct Foo { bar: String, // No default baz: Option = None, } I think this would give us 90% of what I would want from first-class named parameters.

I'm looking for the time to write exactly that RFC. The parser, for what is worth, already parses that syntax for error recovery :)

If you're interested, this is the last public conversation I had about these: https://internals.rust-lang.org/t/pre-pre-rfc-syntactic-suga...

Re: Builder Pattern in Rust

#27

Earlier quoted context omitted.

This pattern is fairly good but doesn't support required arguments.

I haven't filed an RFC yet, but I have a plan that I'm optimistic can land sometime that would let you write: struct User { id: Id, email: EMail, name: String = String::new(), age: u16 = 0, } let user = User { id, email, .. }; // valid let user = User { id, .. }; // complain about email missing It would leverage `const` expressions, so it would desugar effectively to the same as if you had written: const DEFAULT_USER…

This old RFC came up elsewhere in the thread and sounds like a similar idea:

https://github.com/rust-lang/rfcs/pull/1806

Re: Builder Pattern in Rust

#28
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?

Re: Builder Pattern in Rust

#29

Earlier quoted context omitted.

This pattern is fairly good but doesn't support required arguments.

I haven't filed an RFC yet, but I have a plan that I'm optimistic can land sometime that would let you write: struct User { id: Id, email: EMail, name: String = String::new(), age: u16 = 0, } let user = User { id, email, .. }; // valid let user = User { id, .. }; // complain about email missing It would leverage `const` expressions, so it would desugar effectively to the same as if you had written: const DEFAULT_USER…

> assumes that String::new will be const at some point

It has been const since Rust 1.39 (https://doc.rust-lang.org/std/string/struct.String.html#meth...)

Re: Builder Pattern in Rust

#30
I don't actually do any Rust programming but am very interested in the language. With that disclaimer, I find it unfortunate that this pattern requires something to be mutable that wouldn't necessarily need to be otherwise.
Post reply on HN