Hacker News new | ask | show | jobs
by SamReidHughes 4087 days ago
Are you sure your comments are right? It seems to me like the value would be memcpyed, when you pass by value. There is not one unit of memory that is "taken over," or if there was, then Rust would have a serious problem.
3 comments

It might be a terminology thing. Assuming MyStruct only contains values, it will fully live on my_func's stack and nothing needs deallocating on drop. When take_ownership is called a copy of it's value would be passed in, and the original location marked unusable (assuming MyStruct doesn't implement Copy). So yeah, there's isn't any specific memory location being taken over, since there's two locations involved.
> It seems to me like the value would be memcpyed, when you pass by value.

As far as I know, the compiler should not copy in that instance. Rather, it should move.

> There is not one unit of memory that is "taken over," or if there was, then Rust would have a serious problem.

Could you elaborate on that? Rust does have an ownership model, and ownership can be transferred as in the example. What sort of problems would you expect that to cause? If you're worried that it will invalidate existing pointers, the compiler checks that for you. Unless you deliberately circumvent the check, the compiler guarantees that your pointers are valid.

Semantically speaking, the only difference between a move and a copy is that you're allowed to use a copy type afterwards, and you're not allowed to use a move type afterwards. It's still a memcpy. Of course, these may be elided by optimization passes.
> Semantically speaking, the only difference between a move and a copy is that you're allowed to use a copy type afterwards

Are you speaking about Rust specifically, or move in general? I had always understood that move was no more expensive than passing by reference. That is, I had thought the memory was on the heap and didn't need to be copied each time someone new took ownership of that heap space.

I mean in Rust.

> That is, I had thought the memory was on the heap

An example:

    let x = Box::new(5);
    let y = x;
While the 5 is allocated on the heap, when we move x to y, _the pointer itself_ is memcpy'd. That's why Box<T> isn't Copy; as you say, a simple memcpy won't actually duplicate the structure. Make sense?

(and in this case, I'd assume llvm's optimizations would realize the copy is superflous and just elide it, but semantically, that's what's up)

Oh, agreed. But how about this:

    let x = BigExpensiveStruct::new();
    some_function(x);
That won't trigger a big, expensive memcpy of the BigExpensiveStruct, will it? I'd thought that its memory was on the heap.
If that's just a struct, it's stack allocated. So it's not ok the heap in the first place. IIRC, LLVM may optimize passing it to the function by reference though.
> Could you elaborate on that?

If the value isn't passed by (perhaps elidably) copying, that would mean it's getting allocated on the heap and deallocated.

Yes, I had understood the struct's memory to be on the heap. My thinking was, keeping the memory on the heap allows for inexpensive moves. Whereas, the pointer to the heap space may indeed be on the stack, as far as I know.

But I could be mistaken. This is all based on hearsay--just stuff I've read about the Rust compiler. I don't actually work on the compiler myself.

His comment is right in that all of Rust's values do have move semantics by default (checked by the compiler), that's not specific to Box<T>.
The Rust documentation on ownership shows examples of function with reference parameters and Box parameters, but nothing like the OP's `fn take_ownership(obj: MyStruct)` example. Is that an oversight in this page in Rust docs?

http://doc.rust-lang.org/nightly/book/ownership.html

I think it is an oversight: Box isn't particularly special with how it handles ownership, but people do get the wrong impression that Box is the way to have uniquely owned data, whereas it is actually the default. This happens less now that Box doesn't have special syntax, but I agree with you that we may be able to improve those docs in this respect.

Unfortunately, it can be hard to have an example that's simple enough to understand, while still emphasising the right concepts. Hopefully we can find something.

> nothing like the OP's `fn take_ownership(obj: MyStruct)` example.

It uses Box to demonstrate ownership in the first section, but that works the same way with any Rust type unless said type was opted into copy semantics, there's nothing special or magical about Box (at least in that respect), it's just a wrapper for a raw pointer.

I said comments.