oui
oui

Reputation: 113

Are return values shallow copies in Rust?

When returning a value from a function as such

let x = String::from("Hello");
let y = do_something(x);

with

fn do_something(s: String) -> String { s }

Does Rust do a shallow copy (ie copying the stack value of s into y), or does it do something else ? A shallow copy is made when passing, but is it the same behavior when returning it ?

Upvotes: 1

Views: 490

Answers (1)

kaya3
kaya3

Reputation: 51037

A shallow copy is made when passing, but is it the same behavior when returning it?

Ignoring the first part (which is more complicated) and answering just what you want to know: yes, both parameter passing and returning have the same mechanism.

Now to the first part: that mechanism is called "moving", but it also matters whether we're talking about the language semantics (i.e. what the language spec describes as happening according to its abstract execution model) or what actually happens at runtime on a physical computer (which is allowed to be different, so long as the program still does the right thing according to the language spec).

In the language semantics, most types (i.e. those which do not implement Copy) are passed as parameters or returned by "moving", not "copying". The difference is that moving implies a change of ownership, whereas copying implies that the original owner retains ownership but the recipient receives ownership of a copy.

In actual reality, a "move" is likely to be implemented as a copy of the stack value (what you call a shallow copy). However, that is not always the case, as the compiler may optimise how it pleases. Particularly if a function is inlined, then there is no need to make any copies of parameters or a return value; the inlined function will be executed in the same stack frame, so the stack value need not be copied to a different frame. Note that Rust's ownership semantics are required for this optimisation to work: the inlined function might change the value it takes ownership of (if the parameter is declared mut), and that change would be visible to the outer function (since it's done in the same stack frame), if not for the fact that the outer function isn't allowed to use the value after giving up ownership of it.

Upvotes: 6

Related Questions