Hacker News new | past | comments | ask | show | jobs | submit login

Rust has had multi-parameter traits for a very long time - possibly they were never not multi-parameter. All of the binary ops are multi-parameter. The first parameter is just an implicit Self parameter, which does preference it syntactically, but semantically it is not privileged in any way.

The issue that operator overloading math crates come into is that Rust's polymorphism is not only type safe but also makes stronger coherence guarantees than systems like Haskell do. You can't implement all of the things you want because Rust guarantees that adding code to your system is a "monotonic increase in information" - adding an impl is never a breaking change to your public API, and adding a dependency never breaks your build. Haskell does not make these guarantees.

There's no way to "solve this" entirely because there are a bunch of desirable properties for type class systems and they fundamentally conflict, but I think with specialization and mutual exclusion (the latter hasn't been accepted yet) Rust's system will be as expressive as anyone needs it to be while still maintaining coherence.

Of course in this context Wadler's law should be taken into account, and the grandparent poster could maybe revise their strength of opinion about syntactic sugar and recognize that this is about solving a much more complex problem than how to make matrix multiplication look nice. https://wiki.haskell.org/Wadler's_Law




I stand very much corrected. I must admit I wasn't sure and just skimmed a little documentation and didn't see any examples of MPTCs.

> The first parameter is just an implicit Self parameter, which does preference it syntactically, but semantically it is not privileged in any way.

Yes, but I think the syntax was actually what bothered the OP who was complaining about linear algebra. At least C++ has free functions for operators. (I assume, again without knowing, that Rust doesn't, otherwise OPs "demands" should be easy to meet, given specialization.)

I mean any kind of "double * matrix" or "vector * matrix" or ... should be easy to support if operators are free functions and there's MPTC and specialization. EDIT: Actually, come to think of it, for this situation (algebra) you don't really need specialization, you just need overloading. (Since none of the types involved are sub-types of each other. It could be argued that a 1xN matrix ~ N-vector, but that's probably not worth supporting.)

Generally, I just think it's a mistake to even support the magic "dot" notation and thus privileging one operand over any other, but I guess we're getting off topic.

Thanks for the lesson, btw! :)


Again, the issue we run into is with coherence. The Rust team decided that adding a dependency should never in itself break your build, and adding an impl/instance to a library should never be a breaking change. Haskell doesn't make this guarantee. C++ doesn't even typecheck parameters.

Providing this guarantee means establishing what are called orphan rules: you can only `impl Trait for (Type1, Type2, ...)` if a certain portion of those traits and types are defined within the same library as the impl (the exact rules are nuanced, there's an RFC that defines them). The rules that were arrived at as providing the best guarantees unfortunately make it difficult to implement the operator overloading traits in the way a lot of numeric libraries want.

For example, you can't define a trait `Integer` and `impl<T: Integer> Add<T> for T`.

I'm actually not sure what the OP's specific complaint is, but its ultimate cause is something along these lines.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: