Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement multiple traits at once #1281

Open
nrc opened this issue Sep 14, 2015 · 7 comments
Open

Implement multiple traits at once #1281

nrc opened this issue Sep 14, 2015 · 7 comments
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@nrc
Copy link
Member

nrc commented Sep 14, 2015

A little bit of syntax sugar to make working with trait hierarchies easier.

Probably best to restrict to super-/sub-traits. E.g.,

trait Foo {
    fn foo(&self) -> usize;
}

trait Bar: Foo {
    fn bar1(&mut self) -> String;
    fn bar2(&self) -> Foo;
}

impl Foo + Bar for SomeConcreteType {
    fn foo(&self) -> usize{
        ...
    }

    fn bar1(&mut self) -> String{
        ...
    }

    fn bar2(&self) -> Foo {
        ...
    }    
}
@ticki
Copy link
Contributor

ticki commented Sep 15, 2015

I don't like this, as this isn't very readable. Rather implement each at a time.

@Stebalien
Copy link
Contributor

trait Foo {
    fn foo() {}
}

trait Bar: Foo {
    fn foo() {}
}

?

@Stebalien
Copy link
Contributor

I think the really issue here is repeating where constraints. Typing out impl<...> X for Y isn't too annoying.

One solution is to make constraints on a struct apply to all impls of that struct (automatically). Another is to allow re-using generics:

trait Trait {}
trait Trait2 {}

struct Test<A, B, C>(A, B, C) where A: Clone, B: Sync;
for<A, B, C> where A: Clone, B: Sync {
    impl Trait for Test<A, B, C> {
    }
    impl Trait2 for Test<A, B, C> {
    }
}

@eddyb
Copy link
Member

eddyb commented Sep 18, 2015

This came up in #250, as a way to use default implementations of methods of supertraits that are not part of the supertraits themselves: Ord could have impls of all of the PartialOrd methods based on Ord::cmp, your Bar example could have an impl for Foo::foo, etc.
cc @aturon

@cristicbz
Copy link

I'd love this, but why restrict to super/sub traits? My use-case is more about implementing many small traits. I present this for your viewing pleasure. I'd love to rewrite that as:

impl<Scalar, Tail> Mul<Scalar> + Div<Scalar> + Add + Sub + Neg + Zero
                 + Index<usize> + IndexMut<usize>
        for VectorCons<Scalar, Tail>
        where Scalar: Field, Tail: Vector<Scalar=Scalar> {

    type Mul::Output = Self;
    type Div::Output = Self;
    type Add::Output = Self;
    type Sub::Output = Self;
    type Neg::Output = Self;
    type Index::Output = Scalar;

    fn mul(self, rhs: Scalar) -> Self {
        VectorCons(self.0 * rhs.clone(), self.1 * rhs)
    }

    fn div(self, rhs: Scalar) -> Self {
        VectorCons(self.0 / rhs.clone(), self.1 / rhs)
    }

    fn add(self, rhs: Self) -> Self {
        VectorCons(self.0 + rhs.0, self.1 + rhs.1)
    }

    fn sub(self, rhs: Self) -> Self {
        VectorCons(self.0 - rhs.0, self.1 - rhs.1)
    }

    fn neg(self) -> Self {
        VectorCons(-self.0, -self.1)
    }

    fn zero() -> Self {
        VectorCons(Scalar::zero(), Tail::zero())
    }

    fn is_zero(&self) -> bool {
        self.0.is_zero() && self.1.is_zero()
    }

    fn index(&self, index: usize) -> &Self::Output {
        self.get(index)
            .unwrap_or_else(|| {
                panic!("index out of bounds: the len is {} but the index is {}",
                       self.len(), index);
            })
    }

    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        let len = self.len();
        self.get_mut(index)
            .unwrap_or_else(|| {
                panic!("index out of bounds: the len is {} but the index is {}", len, index);
            })
    }
}

Random suggestion: for formatting's sake it'd be nice to be able to swap the impl things around a bit:

impl<Scalar, Tail> for VectorCons<Scalar, Tail>: Mul<Scalar> + Div<Scalar>
                                               + Add + Sub + Neg + Zero
                                               + Index<usize> + IndexMut<usize>
                   where Scalar: Field, Tail: Vector<Scalar=Scalar> {
    /* ... */
}

or something like that.

@cristicbz
Copy link

@Stebalien I like your suggestion from a principled POV, but more rightwards drift would make sad :(

@nrc nrc added the T-lang Relevant to the language team, which will review and decide on the RFC. label Aug 22, 2016
@matthiasbeyer
Copy link

matthiasbeyer commented Oct 24, 2018

Hi. I like the general idea, though I would not support the "moving the impls to the end of the declaration" bit. Rather do:

impl<Scalar, Tail>
    Mul<Scalar> +
    Div<Scalar> +
    Add +
    Sub +
    Neg +
    Zero +
    Index<usize> +
    IndexMut<usize>
    for VectorCons<Scalar, Tail>
        where Scalar: Field,
              Tail: Vector<Scalar=Scalar> {

(No, I'm not paid by lines of code I write 😄 )

Also: Why + for seperating and not ,? : impl Foo, Bar, Baz for Type?


Four years later I don't like that idea anymore. 😎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

6 participants