Allow shadowing self in methods

use foo::self; doesn't work, you need to write use foo::{self};.

Since people are coming up with more and more complicated rules when to allow self as a binding, I feel like it would make the language more inconsistent, not less. If self is only allowed in some functions, wouldn't that be surprising? If a self binding only allows certain types, isn't that inconsistent with how shadowing works for other binding names?

The current situation isn't ideal, but at least it has simple rules:

  • self is a keyword, so it can't be used as a binding name
  • as an exception, self is allowed as method receiver

If self is allowed as a binding name, people will ask why it works as a binding, but not as a const or static. If that is allowed as well, people will ask why it can't be used for field or method names. What if I want to write

fn self(&self) -> i32 {
    self.self
}

Then someone will want to "shadow" Self as well:

mod self {
    struct Self;
}
use self::Self;

These examples are admittedly extreme and not realistic. What I mean to say is that as a rule, keywords can't be used as bindings, and adding exceptions to a rule makes the language less consistent and more surprising.

11 Likes

Ah, fair point.

While I see where you are coming from, from a developers point of view self, in the context of a method receiver, behaves as if it were a binding (apart from the fact it cannot be shadowed). So I would rather say that by allowing the shadowing of self we break even on consistency and gain a little bit more functionality.

This example seems a bit out of scope, I am only proposing the rebinding of self, the semantics of Self wouldn't change. Moreover, I think any statement starting with use is already interpreted quite differently compared to how self is interpreted inside a method receiver.

In any case, are there any solutions, apart from shadowing self, that would resolve the issue of a macro trying to rebind self under the same name?

3 Likes

You can imagine a version of Rust that doesn't have self as a keyword. Instead Methods would have some rule like "the first parameter must have a type Self || &Self || &mut Self || Rc<Self> || etc".

It seems like self as a keyword is really there to save a few characters.

What I'm wondering is how feasible it would be to just remove self as a keyword. To do it in a backwards compatible way would mean to allow any identifier to replace self in a method signature. Does that lead to any ambiguity? I don't think it should...

Then the discussion would no longer be about where self should and shouldn't be allowed. It's an identifier just like any other, there are no surprises there.


The thing that gets surprising is that an implicitly typed first paramater pattern maches differently from an explicitly typed first parameter:

// this
fn foo(&v)
// is the same as
fn foo(v: &Self)
// and different from
fn foo(&v: &Self)

But this confusion already exists with self.

2 Likes

There are a couple of functions which intentionally do not use self to prevent calling them as method. For example Rc::try_unwrap or Rc::get_mut. Making this: Self be acceptable for calling as method would be a breaking change as foo.try_unwrap() on Rc<Foo> where Foo has a try_unwrap method itself would change try_unwrap() from calling Foo::try_unwrap to Rc::try_unwrap.

8 Likes

This would also break by (presumably) turning a method into an associated function.

impl Me {
    fn f(self: &Me) {}
}

This would also (presumably) start working, but not be callable as a method, which would be confusing.

    fn g(self: &[Self]) {}

Edit: Follow up thought, it would also mean it's a breaking change to land the arbitrary self types feature, and that implementing Deref silently changes some associated functions to methods.

2 Likes

This is valid now, it's a method, it needs to stay that way. Clippy doesn't complain. Clippy will complain for self: Self and self: &Self though.

This is currently an error, and should definitely remain at least a warning.

I agree with that, and its generalization: compiling behavior today must be preserved.

And my conclusion is that "method or not based on the type of the first argument" is a no-go, and "method or not based on being named self" is here to stay.

Signature Self type? Valid receiver type? Var = self Var = not_self
var: &Self :white_check_mark: :white_check_mark: Method Associated Function
var: &Ty :x: :white_check_mark: Method Associated Function
var: &[Self] :white_check_mark: :x: Error Associated Function
var: &[Ty] :x: :x: Error Associated Function

(You can't replace the errors with Associated Function as it would be a breaking change to add new receiver types or implement Deref.)

1 Like

self isn't only used as method receiver, but also to refer to the current module:

use std::io::{self, Read};

Removing self as a keyword is not possible.

Recently when implementing some method-rewriting macros in objc2 I had to jump through some hoops because self is special in this regard.

I don't really see this as something that will come up in anyone's day-to-day programming (altough the new example is nice), but more like a useful tool for macro authors, allowing them to create a context that acts identically to a method (while perhaps behaving a bit differently internally).

I think self = self.project(), self = self.inner, and let self in constructors are strong use-cases. I have stumbled into all of these, and wished I could use self instead of this. let this feels like working around the language.

BTW: GitHub code search for let this.


I wouldn't try to restrict types of self binding/shadowing. That's complex to define, and could be unnecessarily limiting. There could be Clippy lints for suspicious uses of self, leaving language definition simpler.

7 Likes

What types are valid receivers for a given implementation is already defined. I'd find that less confusing than something unrelated to Self.

But I'd rather no limit than some new one-off to remember.

Somewhat off topic, but @withoutboats what does "NOT A CONTRIBUTION" mean? I find that usually your comments are quite insightful and very much contribute to the discussions at hand.

(NOT A CONTRIBUTION)

The Apache License contains these clauses:

"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."

3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.

Can't really discuss it further.

1 Like

From what I understood of previous discussions, all of @withoutboats does is the property of his employer, unless explicitly marked as such, and if they didnā€™t wrote ā€œnot a contributionā€ on all of their messages then the Rust project could have ownership (thus legal) issues.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.