Hacker News new | ask | show | jobs
by steveklabnik 2684 days ago
> So to make this work, references would need to be re-written when a move/copy occurs.

Yes! C++ has a concept called "move constructors" that allows for this (this would be that "smart clone" you talk about later in the comment), but we made a decision to not include it. This introduces some nice properties, at the cost of disallowing self-referencing structs.

> I can still see having an easy way to construct self-referential structs being a useful thing, even if the compiler prevents you from moving them.

So, in some sense, this is what the new Pin stuff is about. It lets you say "from this point on, this thing isn't going to move again" and therefore be self-referential.

> I don't understand why oh_no() taking ownership causes f to be copied to a new location.

"Taking owernship" means "move". "move" means "a memcpy from the old to the new location." Rust isn't really special from any other sort of language with value semantics here, other than disallowing you to use the old value, since it was moved out from. Does that make sense?

1 comments

So, in regards to why it's generally not safe to move a self-referential struct, I understand now. My confusion about the memcpy is a tangent ;)

I guess my confusion is that I while realized "move" could mean a memcpy, I didn't realize it always meant a memcpy.

In other words, I thought the compiler would be smart enough to realized the memcpy is unnecessary, even though ownership has been transferred as far as the type system/borrow checker is concerned.

As another example, if you have this situation:

    let x = 45;
    dbg!(x);
    let y = x;
    dbg!(y);
Is there really any reason to allocate separate memory for y, if x is in accessible after y is defined?

Or is this just an implementation detail, and could possibly change in the future?

Also, thanks for being so responsive! I suppose this isn't really the best place to have this discussion ;)

[EDIT] I realize that's not a good example, because 45 will just be copied. But you get what I was trying to show.

Semantically, it’s always a memcpy. In practice, the copy can be elided depending on circumstance. But that’s an optimization, not the semantic.

(And yeah, Copy types are like that too; the only semantic difference between Copy and move is if you can use the old binding.)

Any time! And yeah, the rust forums are probably better but it’s no big deal :)

OK, cool, so in this case it's just that the Rust compiler isn't optimizing away the memcpy. Thanks!