Skip to content

Multiple Implementations of a Trait #7590

Closed

Description

@jmgrosen

According to @cmr, this should be possible:

use std::vec;

struct IndexableThing;

impl Index<uint, ~str> for IndexableThing {
    fn index(&self, rhs: &uint) -> ~str {
        (*rhs).to_str()
    }
}

impl Index<uint, ~[uint]> for IndexableThing {
    fn index(&self, rhs: &uint) -> ~[uint] {
        vec::from_fn(*rhs, |i| i)
    }
}

fn main() {
    let thing = IndexableThing;
    let thing_str: ~str = thing[5];
    println(thing_str);
    let thing_vec: ~[uint] = thing[5];
    println(fmt!("%?", thing_vec));
}

...but it isn't. I get a error: conflicting implementations for a trait, among other errors.

I'm not sure if this is supposed to be possible, but it would be a very nice feature to have.

Activity

  1. catamorphism commented on Jul 4, 2013

    @catamorphism
    Contributor

    I think that this is something @nikomatsakis is planning on fixing. Currently, coherence ignores type arguments to generic traits when determining whether there are multiple implementations of a trait for the same type.

  2. jmgrosen commented on Jul 4, 2013

    @jmgrosen
    ContributorAuthor

    Great, I'll make sure to watch for that commit.

  3. dobkeratops commented on Jul 12, 2013

    @dobkeratops

    I ran into this too (layering traits on eachother): here was my case:-

    // CONFLICTING TRAIT TEST
    // compiles ok until adding (iii) .. desired behaviour would be for this to compile
    
    trait A { }// VertexGrid interface (heightfield, bezier patch..
    trait B { }// trimesh interface
    
    struct P<T> { // heightfield
      i:int}
    
    struct Q<T> { // concrete trimesh of ... (may be more ways of storing)
      i:int}
    
    // (i) heightfield has VertexGrid behaviours
    impl<T> A for P<T> { }
    // (ii) VertexGrid can be viewed as a mesh
    impl<X:A> B for X { }
    // (iii)concrete trimesh has trimesh interface
    impl<T> B for Q<T> { } 
    //^^^^ error: 25:1 conflicting implementations for a trait
    // (iii) conflicting here (ii)
    // ideally i'd hope the error/ambiguity would come *if* i implemeneted B for Q
    
    fn main() { }
    
  4. thestinger commented on Sep 9, 2013

    @thestinger
    Contributor

    This is still an issue.

  5. k4nar commented on Feb 14, 2014

    @k4nar

    I think I encountered this issue too :

    pub struct Point {
      x: f64,
      y: f64,
      z: f64
    }
    
    impl Mul<Point, Point> for Point {
      fn mul(&self, other: &Point) -> Point {
        Point {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
      }
    }
    
    impl Mul<f64, Point> for Point {
      fn mul(&self, v: &f64) -> Point {
        Point {x: self.x * *v, y: self.y * *v, z: self.z * *v}
      }
    }
    
    fn main() {
    
    }
    
    // testcase.rs:13:1: 17:2 error: conflicting implementations for trait `std::ops::Mul`
    // testcase.rs:13 impl Mul<f64, Point> for Point {
    // testcase.rs:14   fn mul(&self, v: &f64) -> Point {
    // testcase.rs:15     Point {x: self.x * *v, y: self.y * *v, z: self.z * *v}
    // testcase.rs:16   }
    // testcase.rs:17 }
    // testcase.rs:7:1: 11:2 note: note conflicting implementation here
    // testcase.rs:7 impl Mul<Point, Point> for Point {
    // testcase.rs:8   fn mul(&self, other: &Point) -> Point {
    // testcase.rs:9     Point {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
    // testcase.rs:10   }
    // testcase.rs:11 }
    // testcase.rs:7:1: 11:2 error: conflicting implementations for trait `std::ops::Mul`
    // testcase.rs:7 impl Mul<Point, Point> for Point {
    // testcase.rs:8   fn mul(&self, other: &Point) -> Point {
    // testcase.rs:9     Point {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
    // testcase.rs:10   }
    // testcase.rs:11 }
    // testcase.rs:13:1: 17:2 note: note conflicting implementation here
    // testcase.rs:13 impl Mul<f64, Point> for Point {
    // testcase.rs:14   fn mul(&self, v: &f64) -> Point {
    // testcase.rs:15     Point {x: self.x * *v, y: self.y * *v, z: self.z * *v}
    // testcase.rs:16   }
    // testcase.rs:17 }
    // testcase.rs:7:1: 11:2 error: expected std::ops::Mul<Point,Point>, but found std::ops::Mul<f64,Point> (expected struct Point but found f64)
    // testcase.rs:7 impl Mul<Point, Point> for Point {
    // testcase.rs:8   fn mul(&self, other: &Point) -> Point {
    // testcase.rs:9     Point {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
    // testcase.rs:10   }
    // testcase.rs:11 }
    // testcase.rs:7:1: 11:2 error: expected std::ops::Mul<Point,Point>, but found std::ops::Mul<f64,Point> (expected struct Point but found f64)
    // testcase.rs:7 impl Mul<Point, Point> for Point {
    // testcase.rs:8   fn mul(&self, other: &Point) -> Point {
    // testcase.rs:9     Point {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
    // testcase.rs:10   }
    // testcase.rs:11 }
    // testcase.rs:7:1: 11:2 error: multiple applicable methods in scope
    // testcase.rs:7 impl Mul<Point, Point> for Point {
    // testcase.rs:8   fn mul(&self, other: &Point) -> Point {
    // testcase.rs:9     Point {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
    // testcase.rs:10   }
    // testcase.rs:11 }
    // testcase.rs:13:1: 17:2 error: expected std::ops::Mul<f64,Point>, but found std::ops::Mul<Point,Point> (expected f64 but found struct Point)
    // testcase.rs:13 impl Mul<f64, Point> for Point {
    // testcase.rs:14   fn mul(&self, v: &f64) -> Point {
    // testcase.rs:15     Point {x: self.x * *v, y: self.y * *v, z: self.z * *v}
    // testcase.rs:16   }
    // testcase.rs:17 }
    // testcase.rs:13:1: 17:2 error: expected std::ops::Mul<f64,Point>, but found std::ops::Mul<Point,Point> (expected f64 but found struct Point)
    // testcase.rs:13 impl Mul<f64, Point> for Point {
    // testcase.rs:14   fn mul(&self, v: &f64) -> Point {
    // testcase.rs:15     Point {x: self.x * *v, y: self.y * *v, z: self.z * *v}
    // testcase.rs:16   }
    // testcase.rs:17 }
    // testcase.rs:13:1: 17:2 error: multiple applicable methods in scope
    // testcase.rs:13 impl Mul<f64, Point> for Point {
    // testcase.rs:14   fn mul(&self, v: &f64) -> Point {
    // testcase.rs:15     Point {x: self.x * *v, y: self.y * *v, z: self.z * *v}
    // testcase.rs:16   }
    // testcase.rs:17 }
    // error: aborting due to 8 previous errors
    // task 'rustc' failed at 'explicit failure', /build/rust/src/rust-0.9/src/libsyntax/diagnostic.rs:75
    // task '<main>' failed at 'explicit failure', /build/rust/src/rust-0.9/src/librustc/lib.rs:453

    It was with 0.9, but someone on IRC said he had the same issue on master.

  6. nikomatsakis commented on Feb 14, 2014

    @nikomatsakis
    Contributor

    It's unclear whether any of these things should be possible. cc #5527

  7. pnkfelix commented on Mar 27, 2014

    @pnkfelix
    Contributor

    Note that we probably are going to make some changes, at the very least to ease the use case of operator overloading. We currently use (only) the Self type for method resolution, but I think everyone would like to see us adopt something more flexible here, if possible.

    In particular I am referring to the discussion of trait method resolution from the winter 2014 workweek, where we discussed putting in something like functional dependencies in order to allow the types of "inputs" to an operator to participate in the trait method resolution process.

    (Of course the details here still need to be ironed out; it will happen via the RFC process. I just wanted to make an explicit note here since I saw some recent chatter about how to accomplish things like #7935.)

  8. japaric commented on Oct 13, 2014

    @japaric
    Contributor

    A updated version of the OP's code compiles today because of the recent multidispatch PR (#17669)

    struct IndexableThing;
    
    impl Index<uint, String> for IndexableThing {
        fn index(&self, rhs: &uint) -> &String {
            unimplemented!();
        }
    }
    
    impl Index<uint, Vec<uint>> for IndexableThing {
        fn index(&self, rhs: &uint) -> &Vec<uint> {
            unimplemented!();
        }
    }
    
    fn main() {}

    (Although, we are likely to convert the Result parameter of the Index trait into an associated output type in the future)

    @nikomatsakis Should this be closed as fixed?

  9. alexcrichton commented on Oct 13, 2014

    @alexcrichton
    Member

    Thanks @japaric!

  10. nikomatsakis commented on Oct 14, 2014

    @nikomatsakis
    Contributor

    @japaric probably should have been closed long ago as "working as intended", but I guess we've expanded the design now such that this use case is actually supposed to work...funny.

  11. k4nar commented on Oct 14, 2014

    @k4nar

    Thanks very much for your awesome work !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions