Skip to content

Commit 1e97d22

Browse files
committed
Revert "RFC to require impl MyStruct to be nearby the definition of MyStruct"
1 parent 8e452d1 commit 1e97d22

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
- Start Date: 2015-02-19
2+
- RFC PR: (leave this empty)
3+
- Rust Issue: (leave this empty)
4+
5+
# Summary
6+
7+
Allow inherent implementations on types outside of the module they are defined in,
8+
effectively reverting [RFC PR 155](https://github.com/rust-lang/rfcs/pull/155).
9+
10+
# Motivation
11+
12+
The main motivation for disallowing such `impl` bodies was the implementation
13+
detail of fake modules being created to allow resolving `Type::method`, which
14+
only worked correctly for `impl Type {...}` if a `struct Type` or `enum Type`
15+
were defined in the same module. The old mechanism was obsoleted by UFCS,
16+
which desugars `Type::method` to `<Type>::method` and perfoms a type-based
17+
method lookup instead, with path resolution having no knowledge of inherent
18+
`impl`s - and all of that was implemented by [rust-lang/rust#22172](https://github.com/rust-lang/rust/pull/22172).
19+
20+
Aside from invalidating the previous RFC's motivation, there is something to be
21+
said about dealing with restricted inherent `impl`s: it leads to non-DRY single
22+
use extension traits, the worst offender being `AstBuilder` in libsyntax, with
23+
almost 300 lines of redundant method definitions.
24+
25+
# Detailed design
26+
27+
Remove the existing limitation, and only require that the `Self` type of the
28+
`impl` is defined in the same crate. This allows moving methods to other modules:
29+
```rust
30+
struct Player;
31+
32+
mod achievements {
33+
struct Achievement;
34+
impl Player {
35+
fn achieve(&mut self, _: Achievement) {}
36+
}
37+
}
38+
```
39+
40+
# Drawbacks
41+
42+
Consistency and ease of finding method definitions by looking at the module the
43+
type is defined in, has been mentioned as an advantage of this limitation.
44+
However, trait `impl`s already have that problem and single use extension traits
45+
could arguably be worse.
46+
47+
# Alternatives
48+
49+
- Leave it as it is. Seems unsatisfactory given that we're no longer limited
50+
by implementation details.
51+
52+
- We could go further and allow adding inherent methods to any type that could
53+
implement a trait outside the crate:
54+
```rust
55+
struct Point<T> { x: T, y: T }
56+
impl<T: Float> (Vec<Point<T>>, T) {
57+
fn foo(&mut self) -> T { ... }
58+
}
59+
```
60+
61+
The implementation would reuse the same coherence rules as for trait `impl`s,
62+
and, for looking up methods, the "type definition to impl" map would be replaced
63+
with a map from method name to a set of `impl`s containing that method.
64+
65+
*Technically*, I am not aware of any formulation that limits inherent methods
66+
to user-defined types in the same crate, and this extra support could turn out
67+
to have a straight-foward implementation with no complications, but I'm trying
68+
to present the whole situation to avoid issues in the future - even though I'm
69+
not aware of backwards compatibility ones or any related to compiler internals.
70+
71+
# Unresolved questions
72+
73+
None.

0 commit comments

Comments
 (0)