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.
Builder Pattern in Rust
41–50 of 93 posts
Re: Builder Pattern in Rust
#42Just 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.
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
#43I 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.
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
#44I 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…
Re: Builder Pattern in Rust
#45Earlier 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?
Re: Builder Pattern in Rust
#46Earlier 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.
Re: Builder Pattern in Rust
#47Earlier 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.
Re: Builder Pattern in Rust
#48I 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 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
#49Where 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.
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
#50I 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.