[Pre-RFC] `trait` & `impl` Blocks Without Bodies (`impl MyTrait for usize; // semicolon`)

I have had this small syntax change idea for a while that would make trait & impl blocks more inline with structs. This change would be purely a syntaxual change, and wouldn't change any semantics about the language. The motivation I have is that this change would make the language feel just a little more consistent.

The change being... accepting trait Trait & impl Trait for X blocks, without bodies. Here's what that would look like, with some erroneous code.

// -----------------
// Before change...
// -----------------

/// My trait.
pub trait MyTrait {
    fn say_hi() {
        println!("Hi!")
    }
}

/// My trait implementation.
impl MyTrait for usize {}

/// My marker trait.
trait MyMarkerTrait {}

/// My marker trait blanket implementation.
impl<T> MyMarkerTrait for T
    where T: MyTrait {}

// -----------------
// After change...
// -----------------

/// My trait.
pub trait MyTrait {
    fn say_hi() {
        println!("Hi!")
    }
}

/// My trait implementation.
impl MyTrait for usize; // Semicolon here, because this implementation inherits from the default implementation on the trait.

/// My marker trait.
trait MyMarkerTrait; // Semicolon here, because MyMarkerTrait doesn't have any associated items.

/// My marker trait blanket implementation.
impl<T> MyMarkerTrait for T
    where T: MyTrait; // Semicolon here, again, because MyMarkerTrait doesn't have any associated items.

Omitting a body on impl Trait for X & trait Trait items is semantically exactly like providing an empty body. For example, this code will parse, but not compile.

trait MyTrait {
    fn implement_me();
}

impl MyTrait for usize; // Need to implement implement_me!

impl MyTrait for u8 {} // Same story here.

The only situation I don't think omitting a body should not be allowed is on impl Structs, because those types of empty implementations don't make any sense, since they don't associate the struct (or item) being implemented on with a trait. Of course, it could be added just for consistency sake, but it probably won't ever be used.

I don't expect this to gain much traction, but if it does, I suppose I'll find out.

I'm certainly guilty of typing this occasionally, but it's not clear that impl Marker for Bar; instead of impl Marker for Bar {} is better enough to be worth having.

Looks like rustfmt doesn't even insist on

impl Marker for Bar {
}

so basically meh to the change -- maybe a nice structured hint in the error message, though.

Also, struct Foo; is different from struct Foo {} (and from struct Foo();), which makes it more worth-while there.

6 Likes