News for hackers. Stuff that matters.
Re:Common Rust Lifetime Misconceptions by k__ on Saturday May 23, 2020 @09:26AM (#23282749)
Coming from JS it was rather counterintuitive for me that a function would "own" a value even if it was ran synchronously and finished.

Also, the whole 'move' terminology sounded to me like Rust would move memory around, but it usually referred to the move of ownership. Also 'consume' didn't make no sense to me. "into_iter consumes a vector" what does it mean? Where does the vector go?

The most valuable info I got about lifetimes was: references/borrowing is usually what you want, so always throw in a &.

Re:Common Rust Lifetime Misconceptions by jacoblambda on Saturday May 23, 2020 @10:57AM (#23283451)
These two stack overflow discussions helped me with 'into_iter' and move semantics.

https://stackoverflow.com/questions/34733811/what-is-the-dif...

https://stackoverflow.com/questions/30288782/what-are-move-s...

There are two types of ownership operations in Rust: consume/move and borrow.

A consume or a move is transferring ownership. Consume is often used because it makes more sense in most cases as a word than move. The function is consuming or eating the variable so it is no longer available for another function to consume/eat. The term move comes from the formal system behind the borrow checker, the "Affine type system".

Borrowing is fairly self explanatory. The function isn't eating the value, it's just looking at it or in the 'mut' case, is modifying it in some way(if food is a good analogy, think adding seasoning or removing a crust).

As for 'into_iter', it basically can be defined as a move, borrow, and/or mutable borrow. This let's you set rules on how the data type may be used. This way the type can be used in most language constructs naturally with the compiler picking the best version based on the constraints of the program.

Apologies in advance if you weren't looking for an explanation and I misread the room.

Re:Common Rust Lifetime Misconceptions by ChrisSD on Saturday May 23, 2020 @10:31AM (#23283226)
"Ownership", "move", "lifetimes", etc have nothing* to do with what happens in the compiled program. It's a kind of static analysis. The closest analogy from the JS world would be what Typescript is to JS. Though that analogy is far from perfect.

If a function "consumes" your owned value that means the value can no longer be used by you. It's swallowed by the function you called. The function may simply drop the value (in which case the memory is likely freed). But it's also able to reuse the underlying buffer or integrate it into another type. Which is where `into_` comes in. It can take the value away from you and give you back another type which is now responsible for managing your original value.

-----

* Note: "nothing" is perhaps a bit too strong but conceptually it helps to think of ownership as its own thing.

Re:Common Rust Lifetime Misconceptions by cesarb on Saturday May 23, 2020 @11:24AM (#23283661)
> Also, the whole 'move' terminology sounded to me like Rust would move memory around

That's exactly what happens: a Rust "move" is under the covers a memcpy().

> but it usually referred to the move of ownership.

That's also what happens. For instance, when you move a Vec, you are moving (through memcpy) only three words of memory (a pointer, the length, and the capacity), but you are also "moving" the ownership of the memory behind that pointer. That is, the new Vec is responsible for managing that memory, and the old Vec can no longer be used.

> Also 'consume' didn't make no sense to me. "into_iter consumes a vector" what does it mean?

It means that it takes ownership of the vector, and doesn't give it back.

> Where does the vector go?

It's destroyed within that function. In the case of into_iter() of a vector, it's broken into its component parts (the pointer, the length, and the capacity), and the struct into_iter() returns (which is not a Vec, but something else) is now responsible for managing the memory behind the pointer, and releasing that memory once it's no longer needed.

Re:Common Rust Lifetime Misconceptions by MetaDark on Saturday May 23, 2020 @02:16PM (#23285080)
> That's exactly what happens: a Rust "move" is under the covers a memcpy().

Not exactly. The Rust compiler is usually pretty smart about optimizing out memcpy for most moves.

For example when returning a large struct from a function, the optimizer could add an "out" reference parameter to the function and the function would directly initialize the return value into that reference.

Re:Common Rust Lifetime Misconceptions by Asraelite on Saturday May 23, 2020 @01:53PM (#23284942)
> That's exactly what happens: a Rust "move" is under the covers a memcpy().

Is it really? I had always assumed that the compiler would almost always optimize a move down to nothing, simply reusing the address. If access to the address is still exclusive, what would be the benefit of moving it in memory?

memcpy sounds like what would happen in the case of a copy or clone, not a move.

Re:Common Rust Lifetime Misconceptions by cesarb on Saturday May 23, 2020 @03:41PM (#23285751)
Yes, the optimizer (LLVM) can often optimize memcpy(), and this is not exclusive to Rust: the same optimizations happen with C and C++ (a well-known trick to avoid some undefined behaviors in C is to do a memcpy(), which the optimizer will then elide). It doesn't change that, before the optimization passes, it's doing the equivalent of a memcpy().

> memcpy sounds like what would happen in the case of a copy or clone, not a move.

In Rust, copy and move are nearly identical; the only difference is that, after a move, the compiler doesn't let you access the old value. Clone is different, since it can be overridden to do anything the programmer desires, but by default, it's identical to copy.

Re:Common Rust Lifetime Misconceptions by mikekchar on Saturday May 23, 2020 @09:53AM (#23282940)
Generally speaking, I've found Rust terminology confusing. For example, why does the `IntoIter` iterator gives you owned values? What the heck does "Into" mean to a Rust developer? There are lots of things like that. I've found that fluency in Rust is partly trying to understand the concepts and partly just learning to understand the specific meanings of certain vocabulary. I've likened it to working with Ruby on Rails. There are a lot of useful facilities, but they practically force you to think exactly like the original author -- who doesn't seem to quite speak like I do.
Re:Common Rust Lifetime Misconceptions by ReactiveJelly on Saturday May 23, 2020 @11:46AM (#23283858)
"Into" means it turns the Vec _into_ an iterator.

Normally an iterator iterates _over_ a Vec or other collection, without moving or destroying the Vec.

There's also iter_mut which iterates over the Vec but allows you to mutate elements in-place.

Those are the 3 big groups of iterators: Immutable, mutable, and the ones that consume (i.e. destroy) the vector.

Re:Common Rust Lifetime Misconceptions by mikekchar on Saturday May 23, 2020 @09:29PM (#23288267)
I think the thing is that because the IntoIter consumes the collection, you are right that it is turning it "into" an iterator... I guess. But for me that's not the intent of what I'm doing. If I use iter() or mut_iter(), I'm also getting an iterator. The fact that it doesn't consume the collection is not the thing I care about. I don't program thinking "Oh, I want to consume this collection when I create the iterator, so let's use into_iter()". I think, "Oh, I want to get owned objects out of the iterator. As a side effect of that, it will consume the collection". For me, anyway, it's just a seriously backwards way of saying what you want.

I find that, similar to my experience with Rails (and Rails developers), once you've drunk the Kool aide, it starts to make sense. You are fluent in the language that is being used and you can't think any other way about it. Even if it is awkward, it seems normal and obvious. But when you first approach it, it can be hard to acquire the idea.

Re:Common Rust Lifetime Misconceptions by wtetzner on Wednesday May 27, 2020 @11:39AM (#23324928)
I could see that. It was a little confusing to me too. At first I couldn't figure out why anyone would want into_iter(). Didn't realize it returned owned objects.

Now that I think about it, how does into_iter() work on a Vec? Is it just copying the data out of the Vec anyway? Because the data in a Vec is allocated on the heap, so how can you get an owned object that isn't just a reference (pointer) to the heap memory without copying?

If that's the case, is the only benefit of into_iter() that you don't have to explicitly deref and copy the items?

Re:Common Rust Lifetime Misconceptions by littlestymaar on Saturday May 23, 2020 @11:17AM (#23283609)
> What the heck does "Into" mean to a Rust developer?

Into means it will consume the value (you don't have it anymore): https://doc.rust-lang.org/1.0.0/style/style/naming/conversio...

Re:Common Rust Lifetime Misconceptions by steveklabnik on Saturday May 23, 2020 @11:22AM (#23283643)
(Please note this document is outdated; you’ve linked to the 1.0.0 docs. This particular page is pretty ok but we don’t ship this at all anymore, and haven’t for years.)
Re:Common Rust Lifetime Misconceptions by ChrisSD on Saturday May 23, 2020 @11:49AM (#23283895)
I think the maintained equivalent would be in the Rust API guidelines:

https://rust-lang.github.io/api-guidelines/naming.html#ad-ho...

Re:Common Rust Lifetime Misconceptions by pretzelhammer on Saturday May 23, 2020 @10:34AM (#23283252)
I also came to Rust from JS! I plan to write an article in the future comparing Rust to Typescript.