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

Multiple Implementations of a Trait #7590

Closed
jmgrosen opened this issue Jul 4, 2013 · 11 comments
Closed

Multiple Implementations of a Trait #7590

jmgrosen opened this issue Jul 4, 2013 · 11 comments
Labels
A-traits Area: Trait system A-typesystem Area: The type system

Comments

@jmgrosen
Copy link
Contributor

jmgrosen commented Jul 4, 2013

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.

@catamorphism
Copy link
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.

@jmgrosen
Copy link
Contributor Author

jmgrosen commented Jul 4, 2013

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

@dobkeratops
Copy link

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() { }

@thestinger
Copy link
Contributor

This is still an issue.

@k4nar
Copy link

k4nar commented Feb 14, 2014

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.

@nikomatsakis
Copy link
Contributor

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

@pnkfelix
Copy link
Member

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.)

@japaric
Copy link
Member

japaric commented Oct 13, 2014

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?

@alexcrichton
Copy link
Member

Thanks @japaric!

@nikomatsakis
Copy link
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.

@k4nar
Copy link

k4nar commented Oct 14, 2014

Thanks very much for your awesome work !

lifthrasiir added a commit to chronotope/chrono that referenced this issue Nov 24, 2014
- `num` dependency is gone. It was only used for floored division
  and it is not hard to copy only that portion from num.
- `Duration + Date` (or so) was blocked by rust-lang/rust#7590,
  which has been subsequently fixed.
- Removed unused `unsafe` checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-traits Area: Trait system A-typesystem Area: The type system
Projects
None yet
Development

No branches or pull requests

9 participants