Syntactic sugar: Implement multiple trait for the same type at once

It's too painful when implementing features for generic constructs, I wish I didn't have to repeat the generic parameter list so many times.

trait A {
    fn a(&self);
}

trait B {
    fn b(&self);
}

struct T<V: Display> {
    v: V,
}

for<V> T<V> where V: Display {
    impl A {
        fn a(&self) {
            println!("{} - <T as A>::a", self.v);
        }
    }
    impl B {
        fn b(&self) {
            println!("{} - <T as B>::b", self.v);
        }
    }
}

I can only write it this way, and the editor document summary is ugly and long.

trait A {
    fn a(&self);
}

trait B {
    fn b(&self);
}

struct T<V: Display> {
    v: V,
}

impl<V> A for T<V> where V: Display {
    fn a(&self) {
        println!("{} - <T as A>::a", self.v);
    }
}

impl<V> B for T<V> where V: Display {
    fn b(&self) {
        println!("{} - <T as B>::b", self.v);
    }
}

See RFC 2089: Implied Bounds. Hopefully one day there will be no need to ever repeat bounds from the type declaration again. (Though, given there's been no movement on it in 5 years, and the stdlib has been removing bounds from its types making it less useful, who knows if it will ever be implemented).

8 Likes

Implicit bounds seem to have some strange side effects. All I wanted was a simple syntactic candy, because I had been writing this over and over again, especially when I changed the generic argument list for the structure, and it was too much work.

For this reason, the editor's outline of the 300-plus lines of code doesn't help me read the code very well anymore.

1 Like

To be fair, that's also a question of editor UX. The outline should hide and/or abbreviate the generics and bounds stuff when the entry is collapsed. (Also, would be nice to better distinguish inherent impls from trait impls.)

Even so, too many entries are displayed. How do you read plain text code without the help of an editor ? Of course, a part of the reason is the syntax of 'Impl Trait for Struct' to violate the logical subject (I mean the center of what we search for when we read the code). Such a sequence makes us unable to find the naked eye to find what we need.If we use the 'for Struct {}' syntax, we not only get a satisfactory editor outline, but it is also a great help for reading the code with the naked eye.

Note that this is part of the concern with the feature -- it would make removing bounds from a type a breaking change, and thus if it were accepted we could never do it again in std.

EDIT: Though admittedly most of the things being removed in std are on methods, not on types. (Like https://doc.rust-lang.org/1.0.0/std/cell/struct.Cell.html has lots of bounds that are no longer there, but they're on the impl, not the struct itself.)

5 Likes

I don't understand why the proposed syntax provides any improvement over the status quo. It's got an extra level of indentation for no reason, it's not even shorter, and the change is detrimental to readability because none of the impls but the first one are close to the type name.

I just don't see the legitimate use case for this. If you are writing many (not just 2!) similar, short impls, that's a sign of missing abstraction, likely a supertrait. And if you are not willing to write 2 such impls, then you need to adjust your expectations.

1 Like

My understanding of abstraction is exactly the opposite of yours: I believe that as long as functionality is complete, we should be inclined to break up a large super trait into independent trait, even though they tend to be implemented simultaneously on the same thing.

I was not implying one should make giga-traits with all the methods in the world. I was suggesting to remove obvious repetition, nothing more.

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