Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does &self still desugar to self: &Self? #211

Closed
mdinger opened this issue Aug 7, 2014 · 9 comments
Closed

Does &self still desugar to self: &Self? #211

mdinger opened this issue Aug 7, 2014 · 9 comments

Comments

@mdinger
Copy link
Contributor

mdinger commented Aug 7, 2014

The methods example (or here) says that &self desugars to self: &Self but if you desugar it, it no longer compiles. Is the desugaring still true? If so, these should be updated.

Here are the examples listed which fail when desugared:

// `&self` is sugar for `self: &Self`, where `Self` is the type of the
// caller object. In this case `Self` = `Rectangle`
fn area(&self) -> f64 {
    // `self` gives access to the struct fields via the dot operator
    let Point { x: x1, y: y1 } = self.p1;
    let Point { x: x2, y: y2 } = self.p2;

    // `abs` is a `f64` method that returns the absolute value of the
    // caller
    ((x1 - x2) * (y1 - y2)).abs()
}

Also fails when desugared:

// This method requires the caller object to be mutable
// `&mut self` desugars to `self: &mut Self`
fn move(&mut self, x: f64, y: f64) {
    self.p1.x += x;
    self.p2.x += x;

    self.p1.y += y;
    self.p2.y += y;
}

Fails when desugared:

// This method "consumes" the resources of the caller object
// `self` desugars to `self: Self`
fn destroy(self) {
    // Destructure `self`
    let Pair(first, second) = self;

    println!("Destroying Pair({}, {})", first, second);

    // `first` and `second` go out of scope and get freed
}
@abonander
Copy link
Contributor

I don't think Self is actually a valid type name because the compiler never lets me use it in impl blocks when implementing traits. I have to fill in the actual type name of the implementing type.

Does this fail:

fn area(self: &Rectangle)

Or does it just not let you call it as a method?

@mdinger
Copy link
Contributor Author

mdinger commented Aug 7, 2014

That fixes it. However, a question on Reddit highlights a case where being explicit with self: &S is harder to use than self. It might just be a bug though. Not sure.

Doesn't work because of lifetimes:

struct S { x: int }

impl Add<S, S> for S {
    fn add(self: &S, other: &S) -> S {
        S { x: self.x + other.x }
    }
}

This works:

impl Add<S, S> for S {
    fn add<'a>(self: &'a S, other: &S) -> S {
        S { x: self.x + other.x }
    }
}

Playpen.

If this behavior is easy to explain, it might be worth explaining. Seems kinda weird.

@abonander
Copy link
Contributor

Maybe &self is implicitly &'a? I couldn't say without delving into the compiler's internals.

@voithos
Copy link

voithos commented Oct 1, 2014

From what I can tell, the primary section of the parser that handles this case is parse_fn_decl_with_self (which, incidentally, also parses the arguments).

There's a nested function maybe_parse_borrowed_explicit_self, which gets executed when the self-pattern begins with an ampersand (as in, &self, or &mut self, etc). Otherwise, it looks for an explicit declaration (as in, self: &mut MyType).

Thus, the sugared syntax is all contained within maybe_parse_borrowed_explicit_self, and are the following (whether or not they have lifetimes can be seen from the function's return values):

  • &self, which is immutable with no specified lifetime
  • &mut self, which is mutable with no specified lifetime
  • &'lt self, which is immutable with a given lifetime
  • &'lt mut self, which is mutable with a given lifetime

However, in @mdinger's example above, I'm not entirely sure how fn add(&self ...) works when the explicit version doesn't. Adding an explicit lifetime to the sugared version fn add(&'a self ...) also works.

@steveklabnik
Copy link
Member

So, what's the result here? I think this is more of a Rust quesiton, and not something really actionable, yes?

@mdinger
Copy link
Contributor Author

mdinger commented Dec 10, 2014

I think an okay approach here would be to change the wording from:

// `&self` is sugar for `self: &Self`, where `Self` is the type of the
// caller object. In this case `Self` = `Rectangle`

To:

// `&self` is sugar for `self: &Rectangle` because the caller is of
// type `Rectangle`. `self` will always refer to the caller's type.

As it was, it's technically worded correctly but slightly misleading.

@mdinger
Copy link
Contributor Author

mdinger commented Dec 10, 2014

It'd probably be good to file a rust bug for self: &Self not working though.

@mdinger
Copy link
Contributor Author

mdinger commented Dec 14, 2014

Looks like this RFC might fix this: rust-lang/rfcs#522

@steveklabnik
Copy link
Member

That RFC was implemented, so this should be fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants