- Feature Name: elide_unused_params_in_impl
- Start Date: 2016-01-11
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)
Summary
Allow impl Trait for Struct<'a, 'b, X, Y>
to be written as impl Trait for Struct
in case
the impl never references its lifetime and/or type parameters.
Motivation
Making code easier to read
impl<'a, 'b, X, Y> Drop for Puppy<'a, 'b, X, Y> {
fn drop(&mut self) { println!("Vooof!"); }
}
In the case above, <'a, 'b, X, Y>
is just visual noise. We should be able to instead write:
impl Drop for Puppy {
fn drop(&mut self) { println!("Vooof!"); }
}
Making code easier to refactor
When a lifetime and/or a type parameter is added or removed from a struct, usually a lot of places also need to be updated. With this change, fewer places need to be updated, making it easier to refactor the code.
Detailed design
Step 1
For impl
blocks such as impl Struct
, impl Enum
, impl Trait for Struct
, and impl Trait for Enum
,
one can skip either all lifetime parameters, all type parameters, or both, provided that there is no
reference to those lifetime and/or type parameters inside the impl
.
Notice the all or nothing rule - a Puppy<'a, 'b, X, Y>
can be shortened to Puppy<X, Y>
, Puppy<'a, 'b>
and Puppy
, but no other combinations are possible.
This is to make sure parameters do not get mixed up with each other.
If the struct/enum has constraints, such as: struct Puppy<X: Eq, Y: Clone>
, those constraints will follow
along in the impl, so impl Drop for Puppy
will be short for impl<X: Eq, Y: Clone> Drop for Puppy<X, Y>
.
(In this case, writing e g impl<X: Copy, Y: Clone> Drop for Puppy<X, Y>
will fail compilation because Copy
does not imply Eq
.)
Step 2
Inside impl
blocks where the type is referenced, that reference will assume
having the same lifetime/type parameters as its impl. This will make the following code valid, which it is not in
step 1:
enum Puppy<'a, X> {
Cute(X),
VeryCute(& 'a str),
}
impl<X> Puppy<X> {
fn new_cute(x: X) -> Puppy<X> { Puppy::Cute(x) }
}
Above, the 'a
will be elided and assumed to be same as the impl, i e it’s short for:
impl<'a, X> Puppy<'a, X> {
fn new_cute(x: X) -> Puppy<'a, X> { Puppy::Cute(x) }
}
Step 3
Once this is done, it seems natural to also extend this to cover free functions, i e,
fn bark<'a, 'b, X, Y>(p: &Puppy<'a, 'b, X, Y>) { println!("Woof! Woof!"); }
can be shortened to:
fn bark(p: &Puppy) { println!("Woof! Woof!"); }
Drawbacks
Every new something adds complexity to the language. I consider the added complexity in this case to be very minor, though.
Feel free to come up with more drawbacks
Alternatives
Stay with status quo.
Unresolved questions
Traits can also have type and lifetime parameters. This RFC does not cover them, it can be done at some later stage.
Disclaimer: No puppies were dropped, or had their lifetimes shortened, while this Pre-RFC was written.