-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Parameterized traits can't be implemented for arbitrary types even if their parameters are "local" #20749
Comments
It turns out the rules from that RFC weren't quite good enough, unfortunately. #19470 |
For the moment, at least, this error is expected. We may revise the rules in the future and plan to (at least) write up a good description of how we arrived at the current rules. |
(re-post from reddit, since this didn't get much attention there, and I think it might be a potential solution to allow overriding binops on both sides) From the new rules , it sounds like the design for the operators should be changed to contain both the LHS and RHS on the Could we do something like this? on trait Add {
type Output;
fn add(self) -> <Self as Add>::Output;
} on user libraries: struct BigFloat;
impl Add for (f64, BigFloat) {
type Output = BigFloat;
fn add(self) -> BigFloat {
BigFloat
}
}
impl Add for (BigFloat, f64) {
type Output = BigFloat;
fn add(self) -> BigFloat {
BigFloat
}
} And then, make |
Plausibly, but it carries limitations as well. For example, one cannot do this:
Perhaps it's a worthy trade-off though. We don't necessarily have to change the trait itself so much as add a way for |
@nikomatsakis I think the following would work for both cases with the current rules. There's more boilerplate but that shouldn't be a too big of a deal. It could be simplified with equality constraints. pub mod tag {
pub enum Add {}
pub enum Mul {}
}
trait OpSelf { type LHS; type RHS; }
impl<LHS, RHS> OpSelf for (LHS, RHS) { type LHS = LHS; type RHS = RHS; }
trait Op<Tag, LHS, RHS>: OpSelf<LHS = LHS, RHS = RHS> { type Out; }
trait Add<LHS, RHS>: Op<tag::Add, LHS, RHS> {
fn add(self) -> <Self as Op<tag::Add, LHS, RHS>>::Out;
}
struct BigFloat;
impl Op<tag::Add, f64, BigFloat> for (f64, BigFloat) { type Out = BigFloat; }
impl Add<f64, BigFloat> for (f64, BigFloat) {
fn add(self) -> BigFloat { BigFloat }
}
impl Op<tag::Add, BigFloat, f64> for (BigFloat, f64) { type Out = BigFloat; }
impl Add<BigFloat, f64> for (BigFloat, f64) {
fn add(self) -> BigFloat { BigFloat }
}
struct MyVec<U>;
impl<U, T: Iterator<Item = U>> Op<tag::Add, T, MyVec<U>> for (T, MyVec<U>) { type Out = MyVec<U>; }
impl<U, T: Iterator<Item = U>> Add<T, MyVec<U>> for (T, MyVec<U>) {
fn add(self) -> MyVec<U> { unimplemented!() }
} |
I think I am seeing a symptom of this with this code: http://is.gd/WbOmdE use std::ops::Shl;
pub trait Subscriber {
type Input;
}
pub trait Publisher<'a> {
type Output;
}
pub trait Processor<'a> : Subscriber + Publisher<'a> { }
impl<'a, P> Processor<'a> for P
where P : Subscriber + Publisher<'a> { }
impl<'a, PR, PB> Shl<Box<PR>> for Box<PB>
where PR : Processor<'a, Input=<PB as Publisher<'a>>::Output>,
PB : Publisher<'a, Output=<PR as Processor<'a>>::Input>
{
type Output = Box<Publisher<'a, Output=<PR as Processor<'a>>::Output> + 'a>;
fn shl(self, rhs: Box<PR>) -> Box<<Self as Shl<Box<PR>>>::Output> {
rhs as Box<PB>
}
}
fn main() {} |
@rrichardson none of the proposed rules allow for that example that you just gave. The problem is that there are no local types in the impl -- just |
Is this issue still here http://is.gd/oX7GWN, or I am doing something wrong ? use std::fmt::{Display, Formatter, Error};
struct MyLocalType;
type MyResult = Result<MyLocalType, String>;
impl Display for MyResult {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
f.write_str("some test string")
}
}
fn main() {
let r: MyResult = Ok(MyLocalType);
println!("{}" , r);
} |
Another example. I wanted to write a Memory trait that supports reading and writing bytes: pub trait Memory {
fn read_u8(&self, addr: u16) -> u8;
fn write_u8(&mut self, addr: u16, val: u8);
} Then I wanted to add convenience methods: everything that implements Memory should just get use std::ops::Index;
impl<M: Memory> Index<u16> for M {
type Output = u8;
...
} Is that not possible? Or am I just doing it wrong? |
This program fails to compile:
The error:
I would expect that this should work because
Add
's parameter is "local" type. Associated types and multidispatch RFC agrees with me.reddit discussion
The text was updated successfully, but these errors were encountered: