I suppose drum.play() could default to using a stick.
musicPart.play(drum, sticks);
Basicslly you can replace the module namespace with a class namespace if desired. What module could that be?What you've done is not OO; in fact, it's an anti-pattern in OO. You've created, as you correctly note, a namespace or module around static functions; there is no meaningful encapsulation of data.
My point isn't that it can't be done, it's that trying to follow best OO practices, you run into this sort of problem (which has had a lot of digital ink spilled on it). The fact there is a pragmatic solution isn't in any doubt; it's that such a solution intentionally eschews the data encapsulation that OO demands (but not imperative or functional approaches, which instead say it's the right approach to do that).
Also, you realize that this whole discussion is proving the point, right?
This is why we can't have nice things.
impl<T> Sound for T where T: Percussion<Accessory=Stick>Here's (really, this is literally the code) how std provides a blanket implementation of Into given From:
impl<T, U> Into<U> for T
where
U: From<T>,
{
fn into(self) -> U {
U::from(self)
}
}
There's actually a chain, From implies Into, Into implies TryFrom, then TryFrom implies TryInto.
In cases where OO doesn't make sense, the solution is to simply provide a functional API instead. Rust stdlib has plenty of such APIs, it's fine to have free-standing functions!