[Idioms/Constructors] use Default instead of empty constructor #276
Replies: 2 comments 2 replies
-
|
Forgot to mention this: having both (I don't know if this principle has a name, like KISS or DRY.) |
Beta Was this translation helpful? Give feedback.
-
|
I want to cite from Elegant Library APIs in Rust:
Also Rust API Guidelines:
@wookietreiber Do you want to make a pull request with the changes you propose? |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
-
TL;DR: Use
Defaultinstead offn new().The constructors section currently shows an example with
fn new(), i.e. a constructor without arguments. For data structures like this, it is often useful to provide aDefaultimplementation.Defaultis used in a few places in libraries, e.g. instdinOption::unwrap_or_default,Result::unwrap_or_default, orEntry::or_default, so it's definitely useful to have.When there is a
Defaultimplementation, and for data structures with empty constructors there arguably should be one, providingfn new()is unnecessary, even counterproductive.My suggestion is to explain exactly this in the constructors section, maybe even using the variants provided below: going from a less capable version (no default), to having a more capable version (with default), to having even less code than in the initial example (derived default).
Note: I know that there is also a section about
Defaultitself. Since I'm advocating forDefaultinstead offn new(), you might even want to swap these sections, so the section aboutDefaultgets read before the one about constructors. I can also imagine to merge these sections.Variant A: only new without arguments
Note: This variant doesn't have a
Defaultimplementation.Variant B: new + manual Default
Note: This example shows duplicated code. But one could also implement
newusingSelf::default()or implementDefaultusingSelf::new(). Which one should I choose? Avoid this unnecessary decision by not implementing both. One might even make the mistake of having different implementations fornewandDefault. #dangerzoneVariant C: new + derived Default
Note: Here, I opted to use
Self::default()innew. But I could also have implemented it asSelf { o: None }. This would be code duplication as well, you just don't see it because of#[derive(Default)].Variant D: only Default
Note: You can't get by with writing less code, which reduces complexity and means less code maintenance.
Drawback
For programmers coming from other languages,
Defaultmay be a new concept. They might look fornewconstructors instead of checking if there is aDefaultimplementation and wonder where the constructor is. This could be handled if rustdoc would more prominently show that there is aDefaultimplementation. Currently, you usually have to scroll way down to see if there is one.Personal Summary
I find having
Defaultin Rust is awesome. I useDefaultfor all of my data structures that are able to be constructed without arguments. Once I realized that it is functionally equivalent to havingfn new()in terms of having a constructor without arguments, and even more functional by being able to be used in places where libraries requireDefault, I have stopped implementingfn new(), and you can too! 😄Beta Was this translation helpful? Give feedback.
All reactions