Convention for functions which return values which are Copy?

#1

We have lots of conventions around method naming, such as:

  • If the method takes a self reference and returns a reference, call it as_xxx
  • If the method takes self by value and returns a value, call it into_xxx

Is there a convention around methods which take a self reference, but return a value because that value implements Copy? into_xxx doesn’t seem right because it doesn’t consume self. as_xxx doesn’t seem right because it doesn’t return a reference.

#2

I believe that the name for that is just xxx:

struct Foo {
    data: usize
}

impl Foo {
    pub fn data(&self) -> usize {
         self.data
    }
}
1 Like
#3

I’m under the impression that I was once told to use to_xxx in that case. I did so, but my code isn’t widely used, so there’s no chance for feedback on that choice in my case :slight_smile:

#4

At the very least, that’s true for non-Copy types. E.g., &str has to_string, which returns a String. But String isn’t Copy.

#5

That sounds reasonable to me.

EDIT: Looks like a lot of methods on Copy primitives like usize are named using to_xxx, but that seems to be only when there are explicit conversions involved (rather than just accessing existing data) like usize::to_le.

#6

Does it matter though for the naming if the return type is Copy? I do remember that my function returned a Vec, so you’re right, but I’m kinda wondering why you’d want to make that distinction.

I do agree with @OptimisticPeach’s suggestions if you’re returning a field of a struct this way, but it does sound somewhat wrong for other use cases.

#7

I’m thinking that if the type isn’t Copy, then you want to make clear that you’re having to construct a new value in order to return it.

My particular use case is a family of container types that, in the normal case, hold types which are Copy. So it works for me. But I think it may be less obvious if you’re not just exposing encapsulated values.

#8

I use to_* for the reference → value case, but I don’t bother to distinguish between Copy and non-Copy. For me, the important aspect is the combination of “does this consume the thing I have” and “do I own the thing I get back”, which leads to as_*, to_* and into_*.

But, those prefixes are only for functions that are logically doing some kind of conversion of the subject value as a whole. In general, I suffix functions that return references, and don’t prefix/suffix anything else.

1 Like
#9

While i agree that your intention may further help you or the user of your function. I think the function signature is enough to tell what it does to say the least.

#10

That’s true, but function signatures don’t help when reading existing code, which is the more common and arguably more important use case.

#11

You mean one have to check the implementation of the following

pub fn swap<T>(x: &mut T, y: &mut T)

or

pub const fn size_of<T>() -> usize

before s/he know what it does? I think name and signature should suffice.

#12

No, I mean that if you’re reading somebody else’s code or code that you wrote a while ago, it’s much easier to read if you can tell what the functions do from their names rather than having to look up their signatures.

2 Likes
#13

Albeit not sacrificing the overall readability of the function:

pub fn usize_data_get_mut_ref(&mut self) -> &mut usize

But something like so:

pub fn mut_data(&mut self) -> &mut usize

Would work nicely.