Am 22.07.2014 18:50, schrieb Allen Welkie: > Can there be two simultaneous implementations of a generic trait? I ask > because I want to extend the Complex class to allow for multiplication by > scalars, so that you can use "a * b" where "a" and "b" can be either > scalars or Complex.
[snip] Something like this was my first attempt in Rust. I was able to define two own types (complex and imaginary) which I could mix with f64 for multiplication, addition, etc. But it required a kind of "double dispatch". Niko explained it here: http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/ Unfortunately, given how these traits are defined now, design requires a bit of foresight. If you want to mix types like this for binary operations eventually, you should probably start this kind of dispatching early on. You can't do that with num's complex struct now. Its Add/Mul/etc impls weren't designed with double-dispatch in mind. For now, you would have to define your own types like I did. But there is a chance that the binary operator traits change. For a binary operator like + and * there is no clear "receiver" (an object you call an add function on). IMHO the operands should be treated equally. One approach that I saw mentioned by Niko (in another blog post I believe) was to use tuples for that: trait Add<Out> { fn add(self) -> Out; } impl Add<Complex<f64>> for (f64,Compex<f64>) { fn add((lhs, rhs) : (f64, Complex<f64>)) -> Complex<f64> { ... } } And this makes it much easier to extend the interface of certain types together. On the other hand, there still needs to go some thought into this with respect to passing operands by value or reference. You don't want unnecessary clones. And you probably don't want operands to be moved-from in some cases. And the way these kinds of traits are refined should work well together with generic code: fn foo<T,U,O>(x: T, y: U) -> O where ???: Mul<O> { x * y } Ideally, this should work for every type T and U that can be multiplied somehow. The question however is, how to write down the type bound? Should we write (&T,&U): Add<O> to avoid moving? Should we write (T,U): Add<O> for a nicer, more intuitive syntax perhaps? I don't know. If you have a good idea how to do that, I'm all ears. I'm very much interested in getting easily overloadable operators without the pain of double-dispatch and without the pain of clumsly type bounds for generic functions that only work for half the cases due to references and such. Cheers! sg _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev