> This is essentially a complaint that Rust went with strongly-typed generics
It could also be a complaint about how operators are implemented, e.g. in Scala they're just methods (no need for a special trait). That's not to say I don't think Rust made the right choice, but Scala went with strongly-typed generics, and can allow implementing the asymmetric multiplication operators.
If operators are just specially named methods, then with strongly-typed generics you can't write generic functions that work on anything that (for example) implements the + operator, because traits (concepts) have to have a specific signature.
Yes, you're right. The only way I can think of to handle it (in Scala, I suppose you can't do it in Rust) would be via implicit parameters. You would basically have a Times trait, and a TimesOp trait.
trait TimesOp[L,R,O] {
def times(L left, R right): O
}
object TimesOps {
implicit object ScalarMatrixTimesOp[S] extends TimesOp[S,Matrix[S],Matrix[S]] {
override def times(S left, Matrix[S] right): Matrix[S] = {
...
}
}
}
trait Times { self: L =>
def *[R,O](R right, implicit timesOp: TimesOp[L,R,O]): O =
timesOp.times(this, right)
}
I'm sure I got something wrong here, but I think the basic idea works. In any case, it goes to show that getting this behavior in a language with strongly-typed generics is non-trivial.
It could also be a complaint about how operators are implemented, e.g. in Scala they're just methods (no need for a special trait). That's not to say I don't think Rust made the right choice, but Scala went with strongly-typed generics, and can allow implementing the asymmetric multiplication operators.