Newcomer to Rust: my experience

Good afternoon and happy easter,

I am a newcomer to Rust and recently finished working through your tutorial. Before I get too much further into reading the standard library, I wanted to share my experience as a complete Rust newbie starting out only with your documentation, before I forget it. I regret that I did not start taking notes immediately, but it was not yet clear to me how much I was going to like Rust, so a lot of this will be me recalling my experience, without notes.

First, my background. I’ve been programming in C++ for 20 years and used MLton (Standard ML) heavily for about 5 years, 4 years ago. I have dabbled with Haskell, but not seriously. So, as far as beginners to Rust go, I suspect I would be the sort of person who should definitely have been able to go through your tutorial and come out at the other end with a clear mental model of the language, as I’ve been exposed to almost all of the concepts before.

1- I had heard about Rust through the odd talk at ML workshops via youtube, although the last ML workshop I attended in person was ~6 years ago. The main thing that raised Rust to my attention was your v1.0 release which was mentioned on Slashdot. A few days ago, I saw a comment posted somewhere that reminded me about it and contained these two keywords: functional + no-GC. That got me interested enough to head over to your main page.

2- I really liked how on the front page there was a feature list that summarised what I could expect from the language. I was surprised not to see a bullet point reaffirming that there was no garbage collector necessary. I then started reading the Rust tutorial “book” in order.

3- Installing Rust on Mavericks worked perfectly and I was happy to see it supported all three major platforms. I almost made the mistake of installing the old rust package in macports (0.12.0) instead of running the new version. From what I’ve read since, this would have been a critical mistake since Rust has evolved so quickly in the near past. Perhaps this package should be either removed or updated.

4- I was a bit annoyed that I had to wade through Cargo stuff before getting to the details of the language, since I was still in the “evaluating if Rust is interesting” phase and had very little interest in packaging minutia in the introduction.

5- Coming from an ML background, I only needed to skim most of the “basics”, taking note of which features were slightly different.

6- The moment I saw “for x in 0…10”, I immediately wanted to know if I would be able to use the “…” notation on my own types.

7- I was again annoyed by the crates/modules/testing sections at the start of Section 3. I had completed reading the “Basics” section and had yet to see why I should care about Rust. The key Rust feature, resource management was still nowhere to be seen.

8- Finally I reached the “Pointers” section I had been basically waiting to get to this whole time. Then I had to wade through pointer problems that any C programmer already knows intimately, before getting to how Rust does things. These two sections, 3.3 and 3.4, are probably the MOST important sections in the entire tutorial, but they come very late and are not well described. I would have expected to see a top-down approach to explanation. A “here is how Rust deals with memory” and THEN “here is how this solves these problems”. Instead, I got a “here are problems you already know” and then a “here’s how Rust does stuff”. Due to this presentation approach, section 3.3 is very disjointed and I didn’t come away from it with a clear idea of how this all works. It is also very jarring, because the rest of the tutorial is pretty Micky-Mouse and then suddenly the main new concept of Rust is explained with only surface detail in two tiny sections—completely inadequately.

9- I entered the “Ownership” section quite annoyed from the terrible preceding section. I still don’t really understand lifetimes, even after having sorted out the way Rust ownership works. These two sections are the worst in the tutorial, while also being the most important!

At this point, I played around with Rust to try and understand the calling convention, move, copy, and borrow. I am pretty sure I understand it now, but I did NOT come away from the tutorial with this understanding. I would have presented the concepts in this order:

  1. Rust moves objects by default. Include example showing that “let y = x” makes “x” invalid afterwards. Explain that this ensures that there is exactly one release to each allocate—something that can easily be understood even without explaining C pointers. Show that this applies to function calls as well; let x = Foo; f(x); println!("{:?}", x); // <-- Bad

  2. Explain that some types can be copied instead. Mention that this is indicated by the “Copy+Clone” trait and show that “let y = x” and “f(x)” leave “x” valid afterwards. Mention that all basic types work this way, but that it is an opt-in feature.

  3. Show the “#[derive(Copy,Clone)]” syntax which is AFAICT nowhere mentioned in the tutorial. You can understand this even without knowing the details of how traits are actually implemented. This shows a user that he controls the choice between move/copy semantics.

  4. Now introduce Box::new(). Explain that it keeps its contents on the heap, but the pointer on the stack. Trust that programmers already know what heap/stack are without a bad recap. Demonstrate that move semantics mean that the heap object is freed exactly once. Perhaps mention that this is like C++'s unique_ptr.

  5. Explain that Box needs a destructor to do the free. Introduce the concept of Drop. Explain Box can never be marked Copy due to needing Drop. Perhaps mention that Copy+Drop are the only two special traits in Rust (is this right?).

  6. Maybe demonstrate another, more expensive, type of resource managed this way in Rust. Mention this automatic drop is something a GC language can’t give you due to the lazy collection of finalizers.

  7. Only now introduce borrowing. The existing explanation is fine, just out-of-sequence.

  8. Now explain lifetimes as being a way to promise that the borrow is shorter than the life of the object or the borrow it came from. I am still unclear about which use of 'a defines the containing lifetime and which the contained. So, this definitely needs to be explained better, but I think it is WAY less important to understand the details of lifetimes than it is to understand the key concepts of: move vs. copy and RAII.

This explanation (at least #1-#7) needs to come much sooner. Definitely still in the Basics sections. Anyway, back to my first-impression timeline:

10- Sections 3.5-3.7 were easy. One and done.

11- Associated Types (3.8). Why does this come before Traits (3.12)?

12- The closures section was very cool. After I understood Traits. Traits are so important in Rust they need to come first! I was missing an explanation of what the syntactic sugar of “Fn(int) -> int” is all about. I only sort-of understood the point about why a closure has undefined size when returned, but it is fine when used as an argument. My gut feeling was that it is somehow because you left the scope of the monomorphized function that produced it.

13- By the time I read “Static and Dynamic Dispatch” (3.13) I was hooked on Rust. At this point I’d already played around with rustc to understand the memory ownership concept. The static+dynamic dispatch is just so elegant, I was sold completely and totally at this point. MLton has to do escape analysis to determine which closures it can monomorphize away. That you put this directly under my control and completely side stepped this issue is just so elegant. Wow.

14- I skimmed over the rest of the sections without any problems.

15- When I searched for where to post my feedback, I ended up on the now defunct mailing list rust-dev.

I have yet to write serious code in Rust, but the confluence of “Just the Right Ideas” ™ has pretty much convinced me. The documentation of the ‘std’ library looks pretty good, a clear upgrade of the Standard ML basis library it is came from. :wink: At the moment I am very hopeful that Rust is the language I’ve been waiting my entire professional career to learn.

Thank you for your work on Rust! I hope my user report can help you improve the experience for the next newbie.

45 Likes

As was posted in the mailing list, this list is for internal discussion about Rust development, not about user experiences or questions.

from the stickied post on the top of the main page:

This is not a support forum. Questions or requests for support using Rust should be directed to Stack Overflow, using the rust tag, or to the user forum. For community-oriented things and announcements, see our subreddit. For real-time discussion about anything and everything, join our IRC channel.

I am not asking for support. I am giving feedback to improve the documentation. From what I can see, I think this is the correct place for that.

10 Likes

This is definitely the right place, and thank you for taking the time to write this up.

3 Likes

Hey @terpstra, thanks for writing this up.

A few things:

  1. A big thing for me to do this week is to re-do the TOC of the book. It’s the way it is for historical reasons, and what I have planned should address a lot of what you’re talking about here.
  2. You’re looking for something very specific, “I already know most of these things and want to figure out how Rust does them.” Our audience also includes people who haven’t done these things, so, for example, explaining the stack vs heap is pretty critical, though again, with my revision I have plans to address this.

Anyway, yeah, that’s all I’ll say for now. Thanks again!

(I would agree that users. is probably a better place, but thery’re both low-enough traffic that it’s not important at the moment)

7 Likes

Hi steve, thanks for taking the time to read my report.

I agree with you that I was looking for something very specific, and that this coloured my view of the book. Of course, everyone has a slightly different background, and as a writer it is hard to prepare a document that is suitable for as many people as possible.

I would think, however, that Rust is very unlikely to be someone’s first programming language (at least today). Therefore, you might want to assume a bit more pre-knowledge and emphasise more how Rust compares and differs from what people probably already know. This means prioritising the “reasons you should care about Rust” and putting sign-posts on issues where Rust behaves in an unexpected way.

Anyway, thanks for your time and thank you for the tutorial.

PS. I agree my post is a mix of things some of which didn’t belong here. I originally wrote it for posting to rust-dev, before realising it was defunct. I could/should have split it up into smaller chunks and only put the documentation commentary here. Sorry for that!

5 Likes

This is really good feedback.

4- I was a bit annoyed that I had to wade through Cargo stuff before getting to the details of the language, since I was still in the "evaluating if Rust is interesting" phase and had very little interest in packaging minutia in the introduction.

I second this. As much as I love Cargo, I don't want to deal with it when just messing around with the language.

6- The moment I saw "for x in 0..10", I immediately wanted to know if I would be able to use the ".." notation on my own types.

I'm pretty sure there's some trait for this, but I'd have to check the RFC to find out which one. I hope we finish documenting all the new stuff that got added through RFCs before 1.0.

At this point, I played around with Rust to try and understand the calling convention, move, copy, and borrow. I am pretty sure I understand it now, but I did NOT come away from the tutorial with this understanding. I would have presented the concepts in this order:

I had a similar experience. I like your order.

15- When I searched for where to post my feedback, I ended up on the now defunct mailing list rust-dev.

How exactly did you end up there? http://users.rust-lang.org/ is linked on the main page, which would also have been an appropriate place to post this.

3 Likes

I actually found the answer to this, but when reading I just wanted to know if I could. No mention had been made about operator overloading by that point in the tutorial. FYI, a..b makes a Range. If you implement the unstable One + Step for your type, that Range implements Iterator.

That's a good question, and I don't remember now. I suspect I just typed "rust mailing list" into google. :slight_smile: The whole project just seemed so open sourcey that I expected a mailing list, not an online forum. Nothing on the subscription page mentions that the list is now defunct. Maybe I'm just old.

1 Like

I agree, but it's going to be very many people's first systems programming language. Many Rubyists, for example, while programming for years, have never heard the words 'stack vs heap.'

14 Likes

As I understood it, this forum was for Rust internal development, not for random user experiences, but if I am wrong so be it.

This specific category is for...

Discussion about the documentation, either the prose docs or the API docs.

I see this post as an attempt to start a discussion about the documentation.

1 Like

To comment on your criticism’s of the Rust Book, I completely agree.

The Rust book has been primarily written by Steve Klabnik, who is not a low level programmer (a Rubyist), and is written for people without systems experience. I am not trying to sound snide writing this, it is the truth. The book is boring as shit to read through for a while if you know anything about low level constructs , and that is a big problem, as the main come-from for Rust is C/C++ programmers like yourself.

I feel like there needs to be a separate document which assumes understanding of lower level topics like types and pointers and low level environments, and I would like that to be the main book, because Rust is meant for low level programmers, not web developers.

Thats just my 2cents, I hope you like Rust, and I except to see a cool new library from you soon :stuck_out_tongue:

2 Likes

Sounds good, to each their own, I think it would be better received on the users channel (or the Subreddit, someone should crosspost this!), but I can definitely see where you are coming from

A few small notes about copy/clone/moves particularly:

x being valid after f(x) is entirely Copy (i.e. nothing directly about Clone). In fact, neither Copy nor Clone are a general form of "copy semantics" as one might find in other languages (particularly C++). The former can only works with a restricted subset of types, and the latter requires an explicit call (it is in fact defined entirely in the standard library, other than the #[derive]).

On a similar note,

While it is true that the compiler will complain about the Drop impl if one tries to implement Copy, I think the underlying reason for not marking Box Copy is more a semantic/programmer-intent one, e.g. C++'s unique_ptr doesn't have a copy constructor/assignment even though C++ doesn't have the same destructor restriction. (Similarly, the reference counted Rc fundamentally can't implement Copy because it needs to bump the reference count on a copy, which can't work. This is also mostly orthogonal to having a destructor or not.)

Copy represents value that can be safely duplicated via a shallow memcpy, which Box cannot due, or else there would be two identical Box's both owning the same allocation (leading to double-frees etc.)

(If anyone is still unclear about this relatively subtle connection between moves and copies etc., one of my SO answers seems to have helped many people, and may help you too. :slight_smile: )

Thanks for writing up your thoughts in such detail!

1 Like

I felt that this response was both rude and inaccurate, particularly where you blamed the layout of the book on the fact that Steve Klabnik is "a Rubyist".

All I gathered from this part of your post is "Steve Klabnik is not a real systems programmer", regardless of whether or not you were trying to be snide.

The Rust book is rather clearly meant as a catch-all, as it should be. It is the responsibility of the reader to skip over parts they are already familiar with; the writer should not be skipping over fundamental concepts on the grounds that some people may already be familiar with some of them. To me, that sounds like "you must already be familiar with systems programming to learn about systems programming", which is ridiculous.

Rust is not "meant" for anyone, and such a view strikes me as complete elitism. Rust is a systems language yes, but there is no entry requirement - a web developer (or, gasp, even a rubyist) should feel free to try Rust, and should not be told "Sorry, go and learn C++ first".

I'd also like to know where you are proposing the line is drawn. A reasonably experienced Java programmer will probably know the difference between the stack and the heap, but perhaps not what a pointer is; anyone who has written only basic C will know what a pointer is, but probably couldn't tell you about move semantics. At what point are people "low level programmers" rather than mere "web developers" or whatever other categories apparently exist?

With that said, I think having a second book is a good idea, but making it the "main book" is not. There are always going to be users who already know at least part of what the main book says, but right now nobody will open it and see that they do not know something that is required - I see no reason to change that.

The OP contains valid criticisms I think (particularly about Traits being too far down).

17 Likes

[quote=“huon, post:14, topic:1816”] x being valid after f(x) is entirely Copy (i.e. nothing directly about Clone). In fact, neither Copy nor Clone are a general form of “copy semantics” as one might find in other languages (particularly C++). The former can only works with a restricted subset of types, and the latter requires an explicit call (it is in fact defined entirely in the standard library, other than the #[derive]).[/quote]

I suggested to use the #[derive] syntax because at this point in the book, Traits have not been covered yet. The #[derive] syntax can be understood as “marking the type for Copy” already, though. I agree that Copy not being implemented via Clone is quite surprising to a C++ programmer who expects copy construction, and this definitely needs a sign-post in the text.

[quote=“huon, post:14, topic:1816”] While it is true that the compiler will complain about the Drop impl if one tries to implement Copy, I think the underlying reason for not marking Box Copy is more a semantic/programmer-intent one, e.g. C++'s unique_ptr doesn’t have a copy constructor/assignment[/quote] Of course you are right that Drop is not the only reason for !Copy. However, when discussing RIAA, I think it important to introduce Drop. When ordering the concepts, I thought that discussion belonged after introducing an object that needs it. That Drop and Copy are mutually exclusive is also important to know.

Re: unique_ptr, oops! I meant auto_ptr. It automatically moves ownership when copied or assigned. That’s the same as in Rust. OTOH, it’s now deprecated and C++ programmers did not like it, so maybe it’s not good publicity. Personally, I think the people who cried about auto_ptr just didn’t have the discipline to use it properly. If the compiler had rejected attempt to use a stale handle, like in Rust, there would have been no cause to complain.

Adding to the comment by @Toby_S, I'd also like to note that Steve may be famous for his contributions to Ruby, but programmed other languages, even including C before and maintained a larger piece of ruby software with a huge C and Java components for a long time. I find this an unnecessary statement as well.

9 Likes

Saw it now on the mail list.

I think explaining heap/stack is important, while I can understand your point with it.

For someone coming from, lately, Java, PHP or any scripting language it’s definitely helpful and if any it’s a good refresh of the knowledge about it.

2 Likes

@sinistersnare: Echoing @Toby_S's comments, this in particular is not phrased constructively. Describing something as "boring as shit" is not helping anyone: the doc maintainer @steveklabnik is consistently amazing about responding to criticism and feedback, but, IME, it is seriously draining when feedback is phrased abusively (even if unintentional). Please be more mindful to tone down the aggression in future: if there's something useful to say, it is almost certainly possible to write it in a way that gets everyone on board.

Private message me (here or IRC) for further questions.

(cf. the code of conduct and moderation policy.)

16 Likes

I agree with this rephrasing. I wanted to be sure that you (and any documentation changes that come out of this thread) aren't conflating the orthogonal ideas of destructors and copying. :slight_smile:

I think you're being overly dismissive: unfortunately for us (fortunately, for black-hats), "just be more disciplined" doesn't really work in practice, "to err is human" after all. In fact, recognition of this inevitable fallibility is one of the reason that Rust exists (and presumably the reason for deprecation: it was found to be too error-prone in practice): the default mode of the language (i.e. safe code) ensures properties that programmers have to enforce manually in languages like C & C++.