Is that true? If so, where is this historical fact documented? This seems strange to me, given that traits are functionally equivalent to type classes in Haskell with the head parameter implicit and special syntax for dot notation. Haskell type classes are for sure not used like mixins. Let’s not forget that Rust traits are not like Scala traits (so the association with Scala leads away from understanding IMO).
The fact that Iterator has a bunch of extra derived methods seems to me nothing more than:
- a way to take advantage of dot syntax, 2) to gain in efficiency for some cases by allowing the user to provide more specialized definitions for derived operations.
Point 2) also applies to Haskell where you can give minimal complete definitions such as with the (>>) (blind) operator which is derived.
Point 1) is just a technical detail to me given that you could also allow all free functions with arity of 1+ to be called like x.f(y), and allow for infix chaining, instead of f(x, y). So here the call syntax of Haskell and Rust differs, but this is only a matter of ergonomics of composition. Haskell achieves superior compositionality with partial application (or “auto currying”) and function composition.
Fundamentally however; traits are still not like mixins because you usually have primitive operations which all derived operations of the trait are based on. (PHP does have a notion of abstract trait members however)
You make a good point about trait being appropriate as hinting at “constraint”. Speaking of constraints, I would probably have chosen constraint as the keyword and removed the head parameter. But of course, this is all contrafactual reasoning. We chose trait and we are sticking with it. All of this discussion is just for fun and posterity.
I do think class would have been even more optimal if we could forget about classes in languages with the usual subtype polymorphism. Haskell is really a beautifully designed language. The notion of a “class of types” is really neat.
I get the usual complexity budget argument. I also use that reasoning from time to time. Recently, I used that argument for try { .. } over catch { .. }. In the case of data vs. struct and enum, I think data is IMO sufficiently clear that it wouldn’t have consumed too much of the budget.