Why cannot we pass T to function, which requires &T

Hi,
I am wondering what is the reason, that I cannot pass the value to the function, which expects immutable reference.
For example this code does not compile:

#[derive(Clone)]
struct A {
    x: i32
}

fn foo(a: &A) {
}

fn make_a() -> A {
  A { x: 42 }
}

fn bar() {
  foo(make_a());
}

In some cases it would lead to slightly more ergonomics (I would not have to put & everywhere, where I compose functions for example).
So, is there some reason where coercing pass by value to reference is undesirable?
My thinking is that, it is caller responsibility to decide whether he borrows value or moves value.
And callee (foo here) only promises, I need to read this value and do not care whether it is borrow or move.

(and yes, I know, that changing signature to:

fn foo<T: Borrow<A>>(a: T)

would make things work).

This sounds a lot like the C++ concept of references, where it looks like you pass the object by value but it gets desugared by the compiler to actually just be passing in a pointer to that object.

It might just be that Rust prefers being explicit over implicit. So if you can pass either with or without the & then there should be some sort of notation (like using generics and AsRef/Borrow) to indicate that.

EDIT: lol, autocorrect

1 Like

There has been some discussion about allowing this, but basically, at the moment, Rust does very little coercions, and prefers to stay explicit.

7 Likes

This idea is known as "Allow owned values where references are expected" in the ergonomics roadmap item and the experimentation tracking item. There's some previous dicussion this IRLO thread, and I also remember hearing of it as "discarding ownership".

(Personally I'm a big fan of it, so long as when it looks syntactically like it was moved, it acts semantically like it was moved -- you get use-after-move errors, it can't extend borrow lengths, etc. To me it feels roughly the same as how you can pass a &mut T to something that only needs a &T.)

7 Likes