Live data from Hacker News

Builder Pattern in Rust

greyblake.com

31–40 of 93 posts

Re: Builder Pattern in Rust

#31
The Ruby counter-example would be even better if it used `Struct` instead of a bare Class: https://ruby-doc.org/core/Struct.html

e.g.

  User = Struct.new(:email, :first_name, :last_name)
or to specify them in any order via kw args:

  User = Struct.new(:email, :first_name, :last_name, keyword_init=true)

Re: Builder Pattern in Rust

#32
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 totally agree. Named parameters are one of those language features which once you use it, you don't want to go back.

Similar to C-like syntax and ADT's / explicit nullability, I think named parameters are just going to be considered the default obvious choice for programming languages in the next 5 years.

Re: Builder Pattern in Rust

#33
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...

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

In which case they should be explicitly provided.

Re: Builder Pattern in Rust

#34
post #12
post #4

Earlier quoted context omitted.

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…

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…

Or you could just have named arguments with defaults, which is a highly ergonomic and well-tested solution to this problem.

Re: Builder Pattern in Rust

#35
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...

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.

Re: Builder Pattern in Rust

#36

Where I've really seen builders be useful is when you have lots and lots of parameters, where most of the time defaults are fine, and you may actually want to pass then around to other parts of the systems, perhaps with different dependencies, who will then further modify them. An example of this would be configuring a client. Your unit tests may want the client to literally just be a function that returns "OK", your…

The thing I really don't like about the builder pattern is that it obscures the possibility space. With named arguments/defult parameters, you know exactly what the fields are you need to consider. With builders, you can wander into an unfamiliar codebase, and you have to read through all the methods on this builder object to understand what's going on.

Re: Builder Pattern in Rust

#37

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…

OT, but how can a value that lives on the heap be const? And how could ownership of a (non-Copy) const be passed somewhere else?

Re: Builder Pattern in Rust

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

> 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.

Re: Builder Pattern in Rust

#39

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.

The nice thing about this pattern wrt mutability is that the mutability is scoped very tightly to the statement, since it's not often that you'd need a builder to live longer than a single statement or at the very most the lifetime of the builder. Although I've had to allow a builder to live longer than a single statement for things in the past, nothing is coming to mind at the moment. Because Rust enforces single ownership of mutable resources, it's not all that bad.

Re: Builder Pattern in Rust

#40
Currently this is the only thing slightly bothering me when writing Rust code, everything else is an absolute blast and I'm loving every second of it.

Hopefully an industry wide best-practice will develop soon on how to deal with the problems outlined in the article.

Does anybody know what a Phantom Builder is? The article teases it but doesn't say anything.

Post reply on HN