Method first parameter self or &self

It seems like there would never be a reason for the first parameter of a method defined in an impl to be self instead of &self because then it would take ownership of the value it is called on. Is that correct or are there cases where self is preferred?

If Self is Copy, I usually make methods take ownership (since there's not really any reason not to.) There's also the case of methods that consume self - things like collect on iterators, or build methods on builders that need ownership.

1 Like

It's correct that taking self takes ownership of the value. It is sometimes preferred or necessary, for example if you are converting the value ala Into::into, or certain types of builder patterns.

Searching the documentation of standard types for '(self' will yield more examples.

In your own code, if you end up with a &self or &mut self method that clones itself or a lot of internal fields for some reason, perhaps consider if self makes more sense.

6 Likes

The reason is that you want to take ownership.

For example, Vec::into_boxed_slice takes ownership so it can (potentially) reuse the allocation, rather than (always) needing to copy it.

6 Likes

Don't think of "giving ownership" as "bad". Rust is not an object-oriented language, you usually work with values, they are the more fundamental type (as opposed to references/pointers).

  • Sometimes, passing through ownership can be an optimization. For example, if you have a Builder that contains fields needed for the final output type of the builder, then consuming self by-value in Builder::build() makes it possible for that function to avoid copying all the necessary fields into the output values.
  • Sometimes, it is a mechanism suitable for ensuring correctness. For example, I've once written a wrapper for an HTTP service that used authenticated encryption with nonces. Nonces must be guaranteed to be unique, so I created a non-Copy type Nonce which was then consumed by my HttpClient::send_request() function, ensuring that it was not possible to send the same nonce twice.
3 Likes

As an aside, I have observed that many of your recent questions are of the form "Why doesn't Rust do thing X like language Y does it?" – I would suggest you to take a step back and try to look at Rust with a fresh mindset, from a bird's eye view, so to speak.

Rust is quite different from many mainstream programming languages out there. Consequently, it is not going to be very productive to try and re-apply idioms exactly as they are in Java or C# or Python or JavaScript or C.

6 Likes

Another case for owned self is methods that must be called last and no more than once, e.g. connection.close(). It can be used for closing of a database handle, or a wrapper for db transaction that has fn commit(self) and fn rollback(self).

5 Likes

Ownership semantics is one of the big features of Rust. So yes, you can do really neat stuff with this. For example using ownership as a token of some invariant, that you can rely on. Like kornel said - ownership guarantees that you can't call both commit and rollback on the same value, just from fundamental rules.

1 Like