Live data from Hacker News

Rust Design Patterns as a Book

rust-unofficial.github.io

31–40 of 49 posts

Re: Rust Design Patterns as a Book

#31

Wait what? You can use dyn on the stack (without a Box)? This has been one of my biggest complaints about Rust: I've been using it for years 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 bl…

Honestly, who cares about not knowing that something was possible if you never wanted it? `dyn` working on the stack is more consistent than it not working on the stack.

I'd say one way to a language more completely is to:

a) Read its stackoverflow pages (not sure about Rust but this helped a ton with C++)

b) Get code reviews from others. The rust community is fairly active, or at least it was back when there was just an IRC channel, I don't know as much now since I don't get onto whatever the medium is today. Ask people if there's an easier way to do something.

c) Read others code. I, for example, like to review some of my dependencies just so I understand a bit more about how they work, and I've picked up a lot from that. I used to get on IRC in the morning while I was kinda getting into my work-day and see if I couldn't help others out, this really taught me a lot.

Re: Rust Design Patterns as a Book

#32

Earlier quoted context omitted.

dyn just requires the object to be behind some kind of pointer. The vast majority of the time, that pointer is a Box or an Rc/Arc, but any form of indirection can work.

Taking a second look at this particular example, I guess it is a bit of a "trick" because of the ahead-declaration of both possible "holder" variables on the stack. It's just... wildly unintuitive that this should be possible. Even if you showed me this code without saying whether or not it should compile, I wouldn't be sure. Here's the train of intuition: 1) dyn requires a pointer that may be to one of multiple type…

I think where your intuition is leading you wrong is that in #2, you are assuming ownership. That is, you're saying "I need a place to put an arbitrary thing." But you don't! A &dyn T doesn't own T, just like a &T doesn't own T. Trait objects are a (pointer to data, pointer to vtable), (may be in the reverse order we don't guarantee layout) and so that pointer can point to anywhere, heap or stack.

Interestingly enough, this was special in Rust 1.0 to Rust 1.5. In 1.5, it finally became non-special. It's interesting because I totally get what you're saying, but at the same time, this is an example of Rust being orthogonal, not special cased.

(It is really hard to address the string thing without an example, to be honest.)

Re: Rust Design Patterns as a Book

#33
Having documents like this is awesome - thanks for building it.

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.

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:

    Foo {
        prop: override_default,
        ...Default::default(),
    }
edit: It's hosted on github, duh, nvm

Re: Rust Design Patterns as a Book

#34

Earlier quoted context omitted.

Taking a second look at this particular example, I guess it is a bit of a "trick" because of the ahead-declaration of both possible "holder" variables on the stack. It's just... wildly unintuitive that this should be possible. Even if you showed me this code without saying whether or not it should compile, I wouldn't be sure. Here's the train of intuition: 1) dyn requires a pointer that may be to one of multiple type…

I think where your intuition is leading you wrong is that in #2, you are assuming ownership. That is, you're saying "I need a place to put an arbitrary thing." But you don't! A &dyn T doesn't own T, just like a &T doesn't own T. Trait objects are a (pointer to data, pointer to vtable), (may be in the reverse order we don't guarantee layout) and so that pointer can point to anywhere, heap or stack. Interestingly enoug…

I think you're right about my intuition, and that's interesting about the syntax change. It could just be that during my learning stage I learned (based on example bias maybe?) that dyn is for owned values, and not just any reference. I'm sure this was never stated explicitly, but somehow that idea got lodged in my brain

For the String thing (really, the Deref thing), further down others weigh in with a case where it doesn't work as expected, and then the workaround &*. The latter is something that feels like it should be a non-op, yet it's required in certain cases like this one to trigger something in the compiler. I'm sure there's some internal reason for this, but from the user's perspective it's, "What does dereferencing and then re-referencing this value have to do with performing what amounts to a cast?"

I want to emphasize that I'm not complaining just to complain, nor placing blame on any specific party. I'm just "reporting a bug" in my learning experience with the language, and trying to provide as much info as possible :)

Re: Rust Design Patterns as a Book

#35
post #27

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. When are design patterns useful? And how are they useful?

Design patterns are intended to be a description of patterns found in the wild — that is, it’s descriptive, not prescriptive. Once distilled to their essence, and documented, and named, it becomes possible to efficiently talk about it and reference it. They are natural things, to be found in wild codebases, that are documented and named here. That they get used and abused, or people come up with terrible names (Class…

Also an addendum — design patterns originate from Christopher Alexander, who was discussing the same fundamental idea but applied to natural architecture (that is, not bounded by strict regulations, laws, complex requirements, etc) in various populations; he noted that communities tend towards certain patterns and trends that work, and apply them repeatedly. But the key difference between Alexander’s pattern architecture and say, a McMansion, is the pattern only acts as a start; depending on its context (including other patterns used) the pattern is modified to fit more appropriately. And everything else is modified in reaction to that.

So the movement of a door changes how the window should be placed, which changes the best position of the sofa, which changes the ideal spot for the door, and so on. So it’s a feedback loop, approaching some optimal state where everything is in harmony with everything else (a state he calls “beautiful”, an inherent property all people recognize even if they cannot produce it themselves) — but because people live in the home, and use it and modify it and change through generations, that harmony is a moving goalpost, always sought but only possible to achieve once abandoned.

The analogy to software development is easy to make, but the key point here is that in usage, patterns are not the end but rather the beginning of a design — they can and should be modified to fit, until it is beautiful

Re: Rust Design Patterns as a Book

#36

Wait what? You can use dyn on the stack (without a Box)? This has been one of my biggest complaints about Rust: I've been using it for years 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 bl…

Honestly, who cares about not knowing that something was possible if you never wanted it? `dyn` working on the stack is more consistent than it not working on the stack. I'd say one way to a language more completely is to: a) Read its stackoverflow pages (not sure about Rust but this helped a ton with C++) b) Get code reviews from others. The rust community is fairly active, or at least it was back when there was jus…

> who cares about not knowing that something was possible if you never wanted it?

I have wanted that feature at times in the past (or something like it), and wasn't able to determine that it would be possible. That's exactly my point.

As for your suggestions: this is indeed one way to gather this knowledge, and I have learned a lot particularly from looking at stack overflow. But I don't think it's ideal when knowledge about fundamental language features has to be acquired by word-of-mouth, because it wasn't conveyed in the course of the normal learning path (official tutorials + discovery through application of learned concepts to new situations where their relevance is self-evident).

Re: Rust Design Patterns as a Book

#37

Earlier quoted context omitted.

Honestly, who cares about not knowing that something was possible if you never wanted it? `dyn` working on the stack is more consistent than it not working on the stack. I'd say one way to a language more completely is to: a) Read its stackoverflow pages (not sure about Rust but this helped a ton with C++) b) Get code reviews from others. The rust community is fairly active, or at least it was back when there was jus…

> who cares about not knowing that something was possible if you never wanted it? I have wanted that feature at times in the past (or something like it), and wasn't able to determine that it would be possible. That's exactly my point. As for your suggestions: this is indeed one way to gather this knowledge, and I have learned a lot particularly from looking at stack overflow. But I don't think it's ideal when knowled…

I guess when I assume a feature is possible, and I want to use that feature, I try it and see if it works.

I also don't typically learn via books myself, I learned rust pre-book, and basically entirely via IRC. To me, that's the default-path. But I get why it's not ideal - a written record (like the one linked) is definitely important to have, and it is a legitimate weakness that they're so nascent.

Re: Rust Design Patterns as a Book

#38

Earlier quoted context omitted.

I think where your intuition is leading you wrong is that in #2, you are assuming ownership. That is, you're saying "I need a place to put an arbitrary thing." But you don't! A &dyn T doesn't own T, just like a &T doesn't own T. Trait objects are a (pointer to data, pointer to vtable), (may be in the reverse order we don't guarantee layout) and so that pointer can point to anywhere, heap or stack. Interestingly enoug…

I think you're right about my intuition, and that's interesting about the syntax change. It could just be that during my learning stage I learned (based on example bias maybe?) that dyn is for owned values, and not just any reference. I'm sure this was never stated explicitly, but somehow that idea got lodged in my brain For the String thing (really, the Deref thing), further down others weigh in with a case where it…

> I want to emphasize that I'm not complaining just to complain,

Oh yeah totally! It is very helpful.

> It could just be that during my learning stage I learned

I mean, I think this is very reasonable and intentional. Trait objects are a pretty niche feature of Rust already, and non-owned trait objects are even more niche than that. The book does guide you towards Box for this reason.

> or the String thing (really, the Deref thing), further down others weigh in with a case where it doesn't work as expected,

Yeah so the trick here is a balance between not wanting coercion willy-nilly, and also making some cases work well. You had cited method calls specifically, and those should work due to auto-ref/deref. The example given isn't about method calls, it's about match not doing Deref coercion. That being said it's really easy to assume that it always does it, because it does do it in the right places most of the time! There's interesting tradeoffs here...

Re: Rust Design Patterns as a Book

#39

Earlier quoted context omitted.

I think you're right about my intuition, and that's interesting about the syntax change. It could just be that during my learning stage I learned (based on example bias maybe?) that dyn is for owned values, and not just any reference. I'm sure this was never stated explicitly, but somehow that idea got lodged in my brain For the String thing (really, the Deref thing), further down others weigh in with a case where it…

> I want to emphasize that I'm not complaining just to complain, Oh yeah totally! It is very helpful. > It could just be that during my learning stage I learned I mean, I think this is very reasonable and intentional. Trait objects are a pretty niche feature of Rust already, and non-owned trait objects are even more niche than that. The book does guide you towards Box for this reason. > or the String thing (really, t…

> The book does guide you towards Box for this reason.

Yeah. And that makes sense, though an aside that explains the broader concept ("Note: dyn is usually paired with Box, but it can be used to describe any reference") would help establish the more generalized understanding (it is possible this aside already exists and I just missed it)

Re: the deref coercion, I do think many cases of this class of problem I'm describing come down to implicit behavior the compiler does to infer certain commonly-used and onerous syntactical elements, to make code cleaner and easier to write. I understand why this was deemed necessary, and it's not as much a problem as "magical" behavior in other technologies, because (seemingly) everything the compiler does implicitly maps directly to an equivalent explicit version.

But it leads to a lot of confusion when those rails eventually break. In terms of brevity, this can be looked at as "gracefully degrading": it makes the normal cases better, and reverts to the "baseline" behavior when you step outside of those. But in the context of learning, it is not such a strict win, because the implicit cases have colored the user's understanding of the language itself, actively hampering their ability to venture off the golden path (or form generalizations about concepts).

I kind of wish the compiler had a "turn off all implicit behavior" option, so that you could learn how everything is done explicitly before turning the helpers back on for the sake of productivity.

Re: Rust Design Patterns as a Book

#40
post #22
post #17

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]). 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…

I find that this kind of pattern can be useful if you have a default implementation for each visit_foo method. For example, suppose that you want to create a traversal that walks through the entire Ast and does something special on just the Name nodes. And another traversal that does something special on just the integer literal nodes. One way to do this is to create a default traversal that walks through the entire…

Or create an iterator and use Iterator::filter, which is probably a bit more idiomatic.
Post reply on HN