Wouldn't &self
better be written ref self
to be consistent with patterns elsewhere?
E.g.
impl Foo {
pub fn f(ref mut self) { ... }
}
so as to be consistent with:
let ref mut foo = an_object;
Wouldn't &self
better be written ref self
to be consistent with patterns elsewhere?
E.g.
impl Foo {
pub fn f(ref mut self) { ... }
}
so as to be consistent with:
let ref mut foo = an_object;
&T
is consistent with &val
inside patterns. &val
matches a reference and puts the pointed to value in val
.
But that's exactly the opposite of what happens for &self
. self
becomes a reference.
Exactly! A pattern and value are meant to be the exact opposite. So the expression Some(1)
makes an Option<u32>
, while the pattern Some(val)
matches some Option<u32>
.
Function parameters are patterns.
&self
is a symtax sugar for self: &Self
and nothing more. Shorter form was introduced as we write it every day.
I understand, all I'm saying is ref self
would be more consistent sugar.
I'd say ref self
is equally inconsistent with &self
since it neither reduce nor adds up any reference.
The ref self
means we have the current object by value but are binding self
to a reference to it, which is different to what you think it will do.
Let's use this example:
struct Foo;
fn type_name<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
impl Foo {
fn ref_method(ref this: Self) {
println!("ref method: {:?}", type_name(this));
}
fn ref_borrow_method(ref this: &Self) {
println!("ref borrow method: {:?}", type_name(this));
}
fn ampersand_self(&self) {
println!("ampersand self: {:?}", type_name(self));
}
}
fn main() {
let f = Foo;
f.ampersand_self();
Foo::ref_borrow_method(&f);
Foo::ref_method(f);
// Foo::ref_method(f); // ERROR: Use of moved value
}
The generated output is this:
ampersand self: "&playground::Foo"
ref borrow method: "&&playground::Foo"
ref method: "&playground::Foo"
If we had ref self
(the ref_borrow_method()
method) as syntactic sugar for a &Self
parameter then we'd actually end up with the self
variable being bound to a &&Self
, adding one more level of indirection. Whereas if we had ref self: Self
, the self
variable would be bound to a &Self
, but we would consume the Self
object by value.
So it might feel more consistent, but using the ref
keyword will add another level of indirection.
I think this "should" is correct and have often wished that Rust used &Self
instead of &self
(etc.) for the same reason. Of course, it's way too late to change something so fundamental about the language.
It's a bit unfair to come up with the example of ref this: &Self
, because here you combine two things (&
on the type and ref
on the variable name). That's not what the original post was about.
@Michael-F-Bryan, what you showed is that the ref_method
indeed returns "&playground:Foo"
, in the same way as the ampersand_self
method does.
Considering that the syntactic sugar places the &
before a variable name – and not before a type – I would agree with @tczajka's original post.
However, as ref this: &Self
actually consumes the value, the ref
syntax could be be dangerously misleading. Afterall &self
is a special sort of syntax anyway, as @Hyeonu pointed out:
Nonetheless, I think @tczajka has a point here. I still prefer &self
though (and dislike ref
anyway).
It should never be too late (but I prefer
&self
anyway).
It's too late to implement without breaking Rust's guarantee of backward compatibility. Thus Rust avoids becoming a negative lesson in edition churn. (I'm looking at you, Python.)
Rust (so far) made an amazing job to correct errors from the past while maintaining backward compatibility (also because of the Editions system).
Either way: I like when people question language constructs (I often do that myself ), and this forum should be a place to get (constructive) feedback on breaking ideas.
This forum (URLO) is an okay place to initiate such exploratory discussions. The parallel Rust forum IRLO is for serious consideration of language and tooling (rustc
, cargo
, etc) changes; many of the language and tooling designers read that forum but seldom visit URLO.
I think the original post didn't mean to propose a language change, but was merely an interesting thought-experiment. For me, as a user, it showed up an interesting perspective.
There is no danger of seeing ref self
in the next version of Rust, so I guess we shouldn't criticize the original idea/thought that badly. I find the idea interesting, so thumbs up from my side
That doesn't mean I want to change the language. I like &self
.
Me too! Given how often we need self: &Self
it's a lot more convenient to be able to simply write &self
.
I'm a bit surprised that this moves the parameter into the function (consumes it):
fn foo(ref x: Foo) {}
Wouldn't it make sense to treat the signature of this function as equivalent to the following, and not move the object into the function?
fn foo(x: &Foo)
After all, this works and doesn't consume:
let a = Foo;
let ref b = a;
let ref c = a;
Now that you say it, it surprises me too.
But indeed it does (playground).
The technical explanation is that passed parameters are value expressions but the initializer is a place expression.
Binding in place for function calls would be backwards-incompatible.
fn foo(ref mut x: i32) {
*x = 0;
}
fn main() {
// n.b. `i32` implements `Copy`
let i = 42;
foo(i);
assert_eq!(i, 42);
let mut j = 42;
let ref mut x = j;
*x = 0;
assert_eq!(j, 0);
}