Live data from Hacker News

An alternative introduction to Rust

words.steveklabnik.com

81–90 of 94 posts

Re: An alternative introduction to Rust

#81
post #61

So basically, anyone who doesn't already really appreciate Rust must not know what a stack is, what a pointer is, or what immutability is? I'm sorry, but this implication enrages me. If I'm just trying to print out "Hello World", why would I use some kind of list and a pointer? You touched on an example of where Rust simplifies non-GC memory management. Its nice that there are various ways to track when you are done…

   > while avoiding about half of its complexity.
If you know how to do this, while staying within Rust's design goals, we'd love to hear about it. I think Rust is no more complex than the problem demands, but I'm biased!

Re: An alternative introduction to Rust

#82

> Rust’s variable bindings are immutable by default, but can become mutable, allowing them to be re-bound to something else From someone reading about these details for the first time: Calling them variable bindings confuses the matter. You say, just moments earlier, that variables are called by that name because they can change over time, they’re mutable . But this variable is immutable? But only sometimes? ! I know…

When faced with similar confusion, I used "bound value" instead of "variable". I thought it might be better.

Re: An alternative introduction to Rust

#83
post #52

Earlier quoted context omitted.

This isn't unique to Rust, in fact, as modern C++ presents the same dilemma. Here [1] is a Stack Overflow question where someone asks how to make a doubly-linked list out of smart pointers, and all the answers either involve shared_ptr or C pointers. Same pedagogical issue: you want to deemphasize the less-safe pointers (in Rust, the ones behind an "unsafe" gate; in C++, the raw C pointers) in favor of the safer abst…

I don't get why they just don't suggest using weak_ptr () for the backwards reference.

There's little benefit to doing so. Because weak_ptr points to a shared_ptr, you are still paying the overhead of the reference counting either way. You might as well just use shared_ptr and have a destructor that unlinks every element from the list.

weak_ptr is basically for managing leaks, not for avoiding reference count overhead. Leaks aren't the problem in a doubly-linked list, however.

Re: An alternative introduction to Rust

#84
post #68
post #29

Earlier quoted context omitted.

3. Unlike other languages, variables can be created tied to a scope outer to the one where they are created. The user can control this by indicating that the lifetime of a variable is the same as that of some variable from an outer scope. This is Rust's big innovation. This isn't quite right (or I'm not understanding what you're trying to say). Given let x = 1; { let y = 1; } there's no way you can make `y` itself li…

I think traits are really confusing (dispatch by input AND output type), there's also trait inheritance, trait bounds, casting things to traits; add type inference to that, lifetime parameters and generics. You get things like struct Foo where P: std::ops::Neg + 'a, ::Output: 'a { foo: &'a Bar , } after further research this makes sense, of course, but looks like non-sense to anyone just trying to learn the language

I've seen this example several times now, and I never got why it was so bad: it's mostly an objection to the namespace qualification syntax if anything. It would actually be written:

    use std::ops::Neg;
    struct Foo where P: Neg + 'a, ::Output: 'a {
        foo: &'a Bar

, }

And with further proposed improvements it would be:

    use std::ops::Neg;
    struct Foo where P: Neg + 'a, P::Output: 'a {
        foo: &'a Bar

, }

Not bad. It's saying "I have a generic structure over a type parameter P tied to a lifetime 'a, and P must overload the unary minus operator".

Re: An alternative introduction to Rust

#85
post #61

So basically, anyone who doesn't already really appreciate Rust must not know what a stack is, what a pointer is, or what immutability is? I'm sorry, but this implication enrages me. If I'm just trying to print out "Hello World", why would I use some kind of list and a pointer? You touched on an example of where Rust simplifies non-GC memory management. Its nice that there are various ways to track when you are done…

> Personally I think Rust could maintain a good portion of its core strength while losing about half of its complexity.

How?

Re: An alternative introduction to Rust

#86
Hm, I too got the sense that it's not clear what the "prerequisites" are for reading the article. Parts of it were really straightforward to me "oh, I know roughly what a stack and the heap are" to confusing "wow, I don't know anything about C++". I think a few distinct guides targeting different sorts of programmers might be the answer here.

But I do like the idea of focusing on ownership and lifetimes more front and center, since that's rust's raison d'etre.

Can you get a hold of Niko's slides from the NYC meetup this week at Bloomberg? I was there, and his overview of ownership and borrowing, using the examples of a book, were actually really helpful for me. For whatever reason, his approach really resonated with me.

Re: An alternative introduction to Rust

#87
post #73
post #58

Earlier quoted context omitted.

Right. When you give an object A a lifetime that makes it live as long as object B, you're effectively putting object A into the same scope, for memory allocation purposes, as object B. This works even if B is in an outer scope. This is a new, and very powerful concept. Any tutorial on this needs to be illustrated. Talking about line numbers is not enough.

This... isn't how lifetimes work. As I said above, there's no lifetime annotations you can use to ensure that y lives as long(aka is in the same scope) as x in the following let x = 1; { let y = 2; } This is also true if you do dynamic allocations: there's fundamentally no way to "promote" variables to a higher scopes just by using lifetime annotations. Lifetimes are a purely passive thing, designed to allow the comp…

You're right. I thought you could use lifetime annotation to force something to be allocated in an outer scope. But Rust doesn't allow that.

Re: An alternative introduction to Rust

#88

Steve, great work! I know how hard it is to write so clearly. The only quibble is that I'd make the middle slog a little bit shorter, maybe laying out the vectors horizontally instead of vertically, so people wouldn't forget what the text was about by the time they get to the end of the diagram.

Thanks! Yeah, the layout could be much better, and it'd be neat if I could use real diagrams with arrows as the pointers, maybe.

I thought this intro started really clearly, but I did get bogged down a bit matching up the pointers as numbers. So yeah, I think diagrams with arrows would be a lot easier to follow. I remember seeing a talk from Niko with animated box/arrow diagrams that changed as a piece of code executed (alongside a code snippet with the relevant code highlighted). That was super slick, and I thought it really helped make things clear.

Also, is it standard to talk about memory growing "down" as the memory locations numerically increase? That's the opposite of my impulse (I would have said that 0xff is the top of memory, and 0xfe is "down" from there) but TBH it's been a while since I took the relevant CS class.

Re: An alternative introduction to Rust

#89
post #68

Earlier quoted context omitted.

I think traits are really confusing (dispatch by input AND output type), there's also trait inheritance, trait bounds, casting things to traits; add type inference to that, lifetime parameters and generics. You get things like struct Foo where P: std::ops::Neg + 'a, ::Output: 'a { foo: &'a Bar , } after further research this makes sense, of course, but looks like non-sense to anyone just trying to learn the language

I've seen this example several times now, and I never got why it was so bad: it's mostly an objection to the namespace qualification syntax if anything. It would actually be written: use std::ops::Neg; struct Foo where P: Neg + 'a, ::Output: 'a { foo: &'a Bar , } And with further proposed improvements it would be: use std::ops::Neg; struct Foo where P: Neg + 'a, P::Output: 'a { foo: &'a Bar , } Not bad. It's saying "…

I think namespace qualification syntax and trait bounds make it more confusing

`::Output: 'a` gives me eye cancer and my intuition is if `P: Neg + 'a` then `P::Output: 'a` is implied (why would it not have that bound if P does?)

the Neg trait's Output IS Self (as Neg)! Why is the bound not transitive?

Re: An alternative introduction to Rust

#90
post #52

Earlier quoted context omitted.

I don't get why they just don't suggest using weak_ptr () for the backwards reference.

There's little benefit to doing so. Because weak_ptr points to a shared_ptr, you are still paying the overhead of the reference counting either way. You might as well just use shared_ptr and have a destructor that unlinks every element from the list. weak_ptr is basically for managing leaks, not for avoiding reference count overhead. Leaks aren't the problem in a doubly-linked list, however.

Thanks for jumping in. Yeah I guess it makes sense.

It just got me thinking into having some kind of data structure examples in Rust as side project, after 1.0 availability.

Now just have to find time for it.

Post reply on HN