Live data from Hacker News

Builder Pattern in Rust

greyblake.com

51–60 of 93 posts

Re: Builder Pattern in Rust

#51

Earlier quoted context omitted.

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

Unfortunately hardly any ORMs support that (especially not EF, argh), and writing custom value-types is a painful experience given C# (still) doesn't support strict typedefs nor mixins.

Re: Builder Pattern in Rust

#52

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…

I assume it would clone the defaults? Otherwise non-`Copy` types would have to be moved out of their const, which you can't do unless it's a refcell (et al).

Re: Builder Pattern in Rust

#53
post #46

Earlier quoted context omitted.

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

There's an interesting commonality here: syntactically, `function(Type1(int), Type2(int))` and `function(type1=int, type2=int)` are almost identical. They differ in that types can help guard against errors elsewhere (within or without that function call), but named arguments let you not care about the order.

I've always wondered: what if languages had no guaranteed argument order, but let you skip explicit naming if all parameters were different types? What kind of idioms would that create? Would it mean more newtypes? Would that be cumbersome?

Re: Builder Pattern in Rust

#54

Earlier quoted context omitted.

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

Unfortunately hardly any ORMs support that (especially not EF, argh), and writing custom value-types is a painful experience given C# (still) doesn't support strict typedefs nor mixins.

If only structs were inheritable, then you could roll your own `struct Wrapper` with operators for implicit conversion, equality, etc, and then extend it with just the name and type. Wouldn't help with the EF pain point though, and I'm sure it might confuse newcomers initially.

Re: Builder Pattern in Rust

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

Default only assigns parameters to their default value based on their type (e.g. "0" for u8), it's not an actual implementation of actual default parameters.

More details about this and what else is lacking in Rust compared to Kotlin:

https://medium.com/@cedricbeust/what-rust-could-learn-from-k...

Re: Builder Pattern in Rust

#56
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's actually worse than Java in that regard since at least, Java supports overloading.

In Rust, you need to come up with a new function for each combination of parameters you want.

Re: Builder Pattern in Rust

#57

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.

> Does anybody know what a Phantom Builder is?

Stab in the dark but I would guess that it's using a phantom type parameter to record the state of the builder with regard to its required parameters. This lets you keep the required parameters out of the builder's own constructor, but make the final `build` function only available if the builder is in the right state -- according to the phantom type.

Re: Builder Pattern in Rust

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

Default only assigns parameters to their default value based on their type (e.g. "0" for u8), it's not an actual implementation of actual default parameters. More details about this and what else is lacking in Rust compared to Kotlin: https://medium.com/@cedricbeust/what-rust-could-learn-from-k...

You can derive the Default trait (this is the most popular use case) or implement it yourself where you can have custom default values.

Re: Builder Pattern in Rust

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

Default only assigns parameters to their default value based on their type (e.g. "0" for u8), it's not an actual implementation of actual default parameters. More details about this and what else is lacking in Rust compared to Kotlin: https://medium.com/@cedricbeust/what-rust-could-learn-from-k...

You can just implement the Default trait yourself and set sane defaults right? At least that’s how I use it, implement the default trait manually to easily return a initialized struct.
Post reply on HN