Live data from Hacker News

Rust for Professionals

overexact.com

61–70 of 103 posts

Re: Rust for Professionals

#61

Earlier quoted context omitted.

> You truly don't find that hard or complicated? This is like saying: "You think a 64bit integer is simple? OK, let's dig into the C memory model, twos complement, overflow CPU flags, how CPU caches are implemented, architectural nuances that can lead to unsynced writes from registers to RAM, etc". In reality most people can just learn that it's a number that holds 2^64 values, not complicated. If you want to really…

> The vast majority of beginners can just learn "& means any number of readers and no writers, &mut means one writer and no readers". But 'beginning' is never the hard part of learning any programming language, at least for a programmer. The hard part is going from having learned the basics to getting stuff done. Rust is harder than any other mainstream language to do that in. The writers in that thread can't even de…

From the standpoint of being productive in Rust, this is what you need to know:

* An object has a lifetime. This generally lasts until overwritten or destroyed at end of scope.

* You can loan out references to this object. You can either have a single &mut, xor an unlimited number of & references, but not both.

* References cannot outlast the lifetime of the object they point to.

* If you have a &mut reference to an object, you can give out another &mut reference to the same object. But you can't use the first reference for the duration of the second.

* Lifetimes can be named, and you can express criteria of the form "this lifetime must at least/most this long."

* Bonus: if you have &mut x, you can give out &mut x.a and &mut x.b at the same time. But you can't give out &mut x while such a subreference is live.

And... that's really all you need. Yeah, there's a lot more rules, and there's definitely fun edge cases around things like temporary objects' lifetimes. But there's no need to know all of that stuff. If you get things wrong, the compiler will come back and slap you in the face and give you an error message--that's the selling point of Rust, getting lifetimes wrong is an error, not silent nonsense--and your task at that point is to figure out if you're really breaking a cardinal rule (two or more mutable references to the same memory location, or references not lasting long enough), or if you didn't enforce sufficiently strict requirements for the bounds of the lifetimes. And the rust compiler is pretty good at telling you what you have to do to get necessary lifetime bounds (sometimes too good--it can suggest fixes to lifetime bounds even when such bounds are unachievable).

I'd compare this to things like name lookup and overload resolution in C++, which are actually horrendously confusing algorithms that almost nobody understands in their entirety. Yet plenty of people can be productive in C++ because the general principles are well-understood, and if you're at the point where you need to descend into the morass of exceptions and exceptions-to-exceptions, you're probably writing confusing code to begin with.

Re: Rust for Professionals

#62

Earlier quoted context omitted.

> The vast majority of beginners can just learn "& means any number of readers and no writers, &mut means one writer and no readers". But 'beginning' is never the hard part of learning any programming language, at least for a programmer. The hard part is going from having learned the basics to getting stuff done. Rust is harder than any other mainstream language to do that in. The writers in that thread can't even de…

From the standpoint of being productive in Rust, this is what you need to know: * An object has a lifetime. This generally lasts until overwritten or destroyed at end of scope. * You can loan out references to this object. You can either have a single &mut, xor an unlimited number of & references, but not both. * References cannot outlast the lifetime of the object they point to. * If you have a &mut reference to an…

But I've never heard a C++ programmer deny that it's a large and difficult language.

I personally never really had a problem with ownership model - probably because what I was doing fell into the simple buckets. Rust's difficulty goes well beyond ownership. I just thought the Rust user forum thread I quoted was a gently funny example of the Rust community's denial: "Rust's not hard, but to get a decent mental model of the borrow checker you need to read the standard library, or if not here's 10000 words on how I think of it". I'm not presenting it as "proof" that Rust is hard - the fact that I couldn't do anything practical with it after more troublesome attempts than with any other language is plenty enough for me to know that. Neither do I think difficulty is 'bad'. Denying it can be though.

Re: Rust for Professionals

#63
post #32

An important “unblocker” for me when learning Rust after decades of other languages was internalizing that assignment is destructive move by default. Like many Rust intros, this sort of glides past that in the “ownership” section, but I felt like it should be a big red headline. If you’re coming from C++ especially, where the move/copy situation is ridiculously confusing (IMO), but also from a simpler “reference by d…

I found the copy/move situation in Rust to be far less intuitive than in C++. In C++, move semantics are obvious because they rely on std::move and the && operator, whereas in Rust, similar behavior seemed to depend on the object type. Even more confusingly, Rust has its own move operator as well, despite destructive move being the default behavior for assignment.

I found it frustrating enough that I put the language down and just went back to using C++.

Re: Rust for Professionals

#64

Earlier quoted context omitted.

This is either wrong or incomplete. When you call a function `f()` with some `&mut`, the callee gets a `&mut`, not a borrowed `&mut &mut`. The callee doesn't borrow the ref mut, it gets the actual ref mut, and for some time you have multiple mutable references in the same scope. How?

The function isn’t borrowing the reference. It’s using the reference to borrow the value thats being pointed to by the reference.

I was looking for the word "reborrowing," which I think is crucial for beginners trying to form an effective mental model of Rust semantics.

Re: Rust for Professionals

#65
post #32

An important “unblocker” for me when learning Rust after decades of other languages was internalizing that assignment is destructive move by default. Like many Rust intros, this sort of glides past that in the “ownership” section, but I felt like it should be a big red headline. If you’re coming from C++ especially, where the move/copy situation is ridiculously confusing (IMO), but also from a simpler “reference by d…

Also very important realization is that things that are moved around (assigned to variable, moved into or returned from a function, kept as a part of the tuple or a field of a struct) must have fixed and known size. And the variable itself is not a handle. It's a fixed sized area in the memory that you named and moved something into it.

This makes completely logical why some things must be Box'ed and borrowed. Why you cannot treat Trait or even impl Trait like any other type. Why sometimes it's ok to have impl Trait as your return type while in other cases it's impossible and you must Box it.

Third important realization is that things borrowed out of containers might be moved 'behind the scenes' by the container while you hold the borrow, so you are not allowed to mutate container while you are holding borrows to any of its contents. So it's ok, to instead hold indexes or copies or clones of keys if you need.

Another observation is that any struct that contains a borrow is a borrow itself. Despite using completely different syntax for how it's declared, created, it behaves exactly like a borrow and is just as restrictive.

Last thing are lifetimes, which don't have consistent (let alone intuitive) syntax of what should outlive what so are kinda hard to wrap your head around so you should probably start with deep understanding what should outlive what in your code and then look up how to express it in Rust syntax.

Rust is syntactically very similar to other languages, but semantically is fundamentally different beast. And while familar syntax is very good for adoption I'd also prefer tutorials that while showing the syntax explain why it means something completely different than what you think.

Re: Rust for Professionals

#66

Earlier quoted context omitted.

From the standpoint of being productive in Rust, this is what you need to know: * An object has a lifetime. This generally lasts until overwritten or destroyed at end of scope. * You can loan out references to this object. You can either have a single &mut, xor an unlimited number of & references, but not both. * References cannot outlast the lifetime of the object they point to. * If you have a &mut reference to an…

But I've never heard a C++ programmer deny that it's a large and difficult language. I personally never really had a problem with ownership model - probably because what I was doing fell into the simple buckets. Rust's difficulty goes well beyond ownership. I just thought the Rust user forum thread I quoted was a gently funny example of the Rust community's denial: "Rust's not hard, but to get a decent mental model o…

That's someone who's defining "mental model" as effectively "build a formal model of how this things worth without actually using formalism for everything." Of course everyone in that thread is coming up with very complicated stuff, because OP explicitly asked them to do so.

Yes, Rust's borrower checker is more complicated than equivalent features in other languages. If you read the writings of the Rust language developers, you'll notice that they basically admit that it's where Rust sinks its entire complexity budget, so there's no room to spend it anywhere else. But I don't think it's too complex--it's not complex enough for average developers to not be productive. I would contrast this with C++'s template metaprogramming, which I believe to be too complex for average developers to be productive (e.g., trying to write templates that switch based on the types of the parameters, especially before if constexpr).

Re: Rust for Professionals

#67
post #32

An important “unblocker” for me when learning Rust after decades of other languages was internalizing that assignment is destructive move by default. Like many Rust intros, this sort of glides past that in the “ownership” section, but I felt like it should be a big red headline. If you’re coming from C++ especially, where the move/copy situation is ridiculously confusing (IMO), but also from a simpler “reference by d…

I found the copy/move situation in Rust to be far less intuitive than in C++. In C++, move semantics are obvious because they rely on std::move and the && operator, whereas in Rust, similar behavior seemed to depend on the object type. Even more confusingly, Rust has its own move operator as well, despite destructive move being the default behavior for assignment. I found it frustrating enough that I put the language…

> In C++, move semantics are obvious because ...

In Rust it's also obvious because every = is a move. Confusion comes from tutorials pretending for too long that it's not.

> whereas in Rust, similar behavior seemed to depend on the object type.

It's best to think of that as an exception to the rule created specifically for numbers and other similar small, cheaply copied things.

If you need to move `a` but `a` has a trait Copy then you copy instead.

> Rust has its own move operator as well, despite destructive move being the default behavior for assignment.

I don't think that's true? Rust has a `move` keyword but it's a part of closure definition that makes it take all the variables from its environment by move, even if it doesn't need it. Unless you are talking about something else...

Re: Rust for Professionals

#68
post #54

the hardest part and barrier are the concepts behind lifetimes/ownership/borrowing not the syntax

I think the hard part is understanding how limited is basic feature set of just Rust.

That you can write very few interesting programs without venturing into the heap with Box, Rc and such and into internal mutability with Cell and RefCell.

Then it quickly raises to the power of other languages and surpasses them with "pay for only what you use" mentality.

Re: Rust for Professionals

#69

Earlier quoted context omitted.

The rust borrow checker has been described in trivial terms many times. The first time I had it explained, as I recall, was as a book. You own a book. `&` - You can lend others the book, they can't fuck with it. `&mut` - You can lend the book to one person, they can fuck with it `move` - You give someone else the book, it's theirs now Or `many reader NAND one writer` Is this a complete explanation? No. But it's quite…

OK, simple issue that a beginning Rust user runs into immediately: - function arguments are moved into the called function - you can call a function with a ref, and then you can keep using it in the calling function, because there is a blanket impl of Copy for refs - you can call a function with a ref mut, and then you can keep using it in the calling function because ... ???

You add '.clone()' or '&', the code compiles, you move on.

Re: Rust for Professionals

#70

Earlier quoted context omitted.

> Rust is harder than any other mainstream language to do that in. It's not hard, you just add boilerplate. Cloning data, using interior mutability, or adding ref counting to deal with cases where multiple "owners" can keep an object around independently. Then removing the boilerplate is how you do optimization, once you've gotten things to work. The opposite of other languages where low-level code is the most verbos…

> It's not hard, Yep, that's the standard Rust aficionado flat insistence: "You're finding it hard. You're just wrong". Yet with more learning time than I've put into any other language I've learned, I have been unable to use Rust for real (ie. beyond beginner toys). A quick count of langs I've used professionally comes to about 10; I've learned many more to play with, much more successfully than with Rust, in much l…

Just to be clear, again, lots of people find rust difficult. I found it easy. Lots of people find it easy. That's interesting.

Saying "rust is difficult" is silly to me because... it wasn't for me. Saying "rust is easy" is less silly to me because for me it was, but obviously for you it will be more silly because it isn't easy for you.

You'll find that many in the rust community are in fact very very sympathetic to your view that it's too hard to learn.

Post reply on HN