A very low-effort way to learn good Rust patterns is to put<p><pre><code> #![warn(clippy::all)]
</code></pre>
at the top of your crate’s entrypoint. This enables Rust’s default linter. It’s a lot more friendly and focused on good design than you might expect, often suggesting more elegant alternatives. Plus, many of its suggestions can be applied automatically in an environment like VS Code + rust-analyzer plugin.
Wait what? You can use dyn on the stack (without a Box)?<p>This has been one of my biggest complaints about Rust: I've been using it for <i>years</i> at this point. I read most of the Book, I've read a few unofficial books. And I do love the language, but it has so many cases like this where things that you're allowed to do (syntactically or otherwise) are somehow so non-obvious that you can miss them entirely. I still get blindsided by something like this every couple months, and I always end up a little mad that I've been doing things the hard way until some obscure unofficial material (or more often, a stack overflow answer) teaches me about an entire feature that I didn't know existed.<p>Rust is really great at telling you what you can't do, and in many ways its documentation is incredibly thorough, but it has a real problem when it comes to discoverability and establishing a consistent mental-model of what its syntax actually means (and how you can then apply it to other situations). I don't know what the root cause of this problem is. But it's really distressing to me each time I discover a huge blind-spot; it makes me feel like I never fully understood the language concepts that I thought I understood.<p>I say all of this out of love: I really want Rust to succeed. I still prefer to use it despite this issue. I just believe this is a huge thorn in its side, especially when it comes to adoption, for which it already has an uphill climb.
A list of design patterns for a language amounts to a list of weaknesses in the language or in its library.<p>If the pattern could be captured in a library, that pattern would just be using the library. If the core language provided the feature, the pattern would just amount to using the feature.<p>Generally it is better to improve the language to the point where the feature can be added as a library component, but sometimes that is too hard. Thus, for most languages nowadays a "dictionary" type is provided in the core language, because a useful hash table library cannot be written with language primitives. In C, hash tables are open-coded again in each place where one is needed, because the language provides neither the feature, nor facilities sufficient to capture it in a library. Rust is powerful and expressive enough that hash tables are library components.<p>Conversely, pattern matching and coroutines are built into Rust. It should never be forgotten that (1) this was because the language was not expressive enough to capture the features satisfactorily in a library; and that (2) it would be better if, someday, the core feature became unnecessary because the language became expressive enough provide it as a library.<p>One reason it is better for features to be provided in a library is that another library can implement a variation on the feature that might not be as widely useful as the core version, but is better tuned to a less-common but still important use.<p>Another is that users can invent whole new features by combining powerful primitives that the language designers would not have time, or possibly inclination, to implement themselves.<p>Thus, in a certain sense, all patterns are anti-patterns.
Is there anything that can be achieved by using the visitor pattern [0], that cannot be done by using pattern matching? I have only used the visitor pattern in languages that do not have pattern matching as a language feature (e.g. Java before it got a Scala-like `switch` construct [1]).<p>Edit: one limitation of pattern matching is, that all values need a common supertype (e.g. be variants of the same enum in Rust, if we see each variant as a type and the enum as the common supertype. There is an RFC [2] to make enum variants accessible as types), while the visitor pattern could be implemented for any set of independent types. On the other hand, you then cannot have a typed collection/container that contains values of these types, so you'd need some common trait like `Visitable` so you could accept an `Vec<dyn Visitable>`.<p>[0]: <a href="https://rust-unofficial.github.io/patterns/patterns/visitor.html" rel="nofollow">https://rust-unofficial.github.io/patterns/patterns/visitor....</a><p>[1]: <a href="https://openjdk.java.net/jeps/8213076" rel="nofollow">https://openjdk.java.net/jeps/8213076</a><p>[2]: <a href="https://github.com/rust-lang/rfcs/pull/2593" rel="nofollow">https://github.com/rust-lang/rfcs/pull/2593</a>
In section 2.10, "Privacy for extensibility", are there any pros and cons to this approach over using the #[non_exhaustive] attribute? The latter works on both enums and structs, and doesn't require extra fields to be included.<p><a href="https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute" rel="nofollow">https://doc.rust-lang.org/reference/attributes/type_system.h...</a>
Once you get past writing a language idiomatically, is a list of design patterns a good thing? It is an obvious negative for code readability because it reduces the number of people who can clearly understand your code from Rust users to Rust users who also memorize design patterns.<p>When are design patterns useful? And how are they useful?
I'm a bad man, and I have sinful [ooo] thoughts, but...<p>Is-a inheritance is extremely useful for creating extensible components. "It may
be wrong, but it's much too strong."<p>In rust, how can you make a component that is just like another component, but ever so slightly tweaked without copying the entire external API of that other component? I understand I can wrapper with has-a relationship, intercept the correct API, and then pass through the rest of the entire interface, but how can I avoid copying the entire interface of the object when I only want to tweak something tiny?<p>With a car, I can swap out the engine with another, I just have to make sure the external interface is the same.<p>It may be a "bad thing", but it is extremely useful for the scenario where I say, "I want a Chevy smallblock, but I want to only tweak metal alloy on the interior piston."<p><pre><code> class MyBlock(ChevySmallBlock):
def get_interior_alloy(self):
return metals.Unobtanium
</code></pre>
Bam. I have same item; slightly tweaked. I've used this type of pattern to great effect and I find that style of inheritance manipulation invaluable in python.<p>How can you do this with rust? I know that is-a inheritance is sinful, but show me the better way! I truly want to know it, and I've been trying to find a pattern for this.
Having documents like this is awesome - thanks for building it.<p>Is there somewhere I can PR? One example - the `new` constructor takes no arguments, so at minimum there should be a note about the (mentioned-next) Default pattern.<p>Also, I don't think Default is most useful for abstracting construction (I think closures are better for this), they're really just to make construction easier imo ie:<p><pre><code> Foo {
prop: override_default,
...Default::default(),
}
</code></pre>
edit: It's hosted on github, duh, nvm
Some idiomatic suggestions seemed to replace lacking language features, which is a smell to me; I think it's best to use the language as designed instead of creating something weird and maybe even unstable like a "finally" block using the Drop trait for a dummy struct.<p>Design patterns were weird too. The builder pattern to hide complex initialization? Not a fan; maybe it would be best to remove the complexity instead? Rust is a functional language, so OOP patterns seem like an anti-pattern.
kinda related topic: im debating if I should learn Rust.<p>I'm attracted to Go, but at the end of the day I can do everything that Go can with Nodejs minus the speed part.<p>Rust has just way to many new concepts to simply learn it.<p>Why did you learn Rust over Go. How are you using it?
Patterns are nice, but dangerous to follow blindly in an immature and fast growing industry operating like a pop culture. As an example the book suggest to use YAGNI, a pattern/principle Jim Coplien suggest we fight. I’m inclined to agree. Plan ahead when you can. And btw pull in decisions to get early feedback in stead of delaying to the last responsible moment. Just some thoughts, but I like that patterns are collected for different contexts. It allows for discussion and learning.