Live data from Hacker News

Builder Pattern in Rust

greyblake.com

41–50 of 93 posts

Re: Builder Pattern in Rust

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

Re: Builder Pattern in Rust

#42
post #10

Just add default / optional / named parameters to the language and be done with it.

I doubht that they have enough Ascii characters left over at this point to do it comfortably.

With trait vs fn / impl it is a pinnacle of naming consistency.

On a serious note I have it in my plans to do some semi serious project in it but every time I look at how I should deal with the lack of some common features makes me drop it. So unless specifically requested by clients of mine I inclined to ignore it for now.

Re: Builder Pattern in Rust

#43
post #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.

Named parameters in C# make refactoring far less error-prone too.

Consider a method that accepts two int parameters: “DeleteUser(int tenantId, int userId)” - if a call-site was DeleteUser(1,2) and you swapped the parameter arguments you’d be in trouble. Having “DeleteUser(tenantId: 1, userId: 2)” makes code not only safer, but also far more self-documenting.

Re: Builder Pattern in Rust

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

It is useful in embedded. For example, you may see something like [1]: let _clocks = rcc .cfgr .hse(HSEClock::new(25_000_000.Hz(), HSEClockMode::Bypass)) .sysclk(216_000_000.Hz()) .hclk(216_000_000.Hz()) .freeze(); where the freeze function does a lot of calculation to set up the peripheral [2]. [1]: https://github.com/stm32-rs/stm32f7xx-hal/blob/0a0d06d5f63c3... [2]: https://github.com/stm32-rs/stm32f7xx-hal/blob/0a…

It would be the same for named arguments, yes? Only it would be the constructor doing the set-up work.

Re: Builder Pattern in Rust

#45

Earlier quoted context omitted.

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?

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.

Re: Builder Pattern in Rust

#46
post #32

Earlier quoted context omitted.

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.

Named parameters in C# make refactoring far less error-prone too. Consider a method that accepts two int parameters: “DeleteUser(int tenantId, int userId)” - if a call-site was DeleteUser(1,2) and you swapped the parameter arguments you’d be in trouble. Having “DeleteUser(tenantId: 1, userId: 2)” makes code not only safer, but also far more self-documenting.

At the risk of being pedantic, I would use separate types there for the id's to avoid this kind of issue, but in general I agree with your point

Re: Builder Pattern in Rust

#47
post #32

Earlier quoted context omitted.

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.

Named parameters in C# make refactoring far less error-prone too. Consider a method that accepts two int parameters: “DeleteUser(int tenantId, int userId)” - if a call-site was DeleteUser(1,2) and you swapped the parameter arguments you’d be in trouble. Having “DeleteUser(tenantId: 1, userId: 2)” makes code not only safer, but also far more self-documenting.

In theory, those two types shouldn’t be ints, but rather separate int wrapping types TenantId and UserId so that they can’t be mixed up at all

Re: Builder Pattern in Rust

#48

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.

> With that disclaimer, I find it unfortunate that this pattern requires something to be mutable that wouldn't necessarily need to be otherwise.

It does not, you can also have the builder consume itself. But it’s often less convenient.

The consumption also allows for required parameters through the builder pattern: have the “configuration” method return a different type. It's essentially a statically typed state machine.

Re: Builder Pattern in Rust

#49

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…

Why is this better than a configurable config object that you pass around? I'm downvoted but I am legitimately curious.

I don't think it's a bad question, and it's not like there's a right or wrong answer to any of it. To me, the reason why in the example I gave a builder is better than a config object is because objects necessitate all their fields to be set upfront.

You could then say, "Well why don't you just have getters and setters for all of those fields?". And it's like, ok sure, we could do that, but what if something else is using that object and we're mutating it?

So then you could say, "well what if the setters return a *copy* of the object, the you can then pass along?" And then it's like, ok, well now we basically have a builder, we're just calling it different things.

Re: Builder Pattern in Rust

#50

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.

It doesn't need to be mutable, it's just more efficient. Also the mutability only exists within the builder methods - you can build the struct and assign it to an immutable variable.
Post reply on HN