4 ms·
Yes, Rust traits are Haskell typeclasses. What he's saying has no parallel in most other languages are the `impl` blocks (which can be used to both define arbit
by mernen 4y ago
Yes, Rust traits are Haskell typeclasses. What he's saying has no parallel in most other languages are the `impl` blocks (which can be used to both define arbitrary methods and implement traits, the latter being directly analogous to Haskell's `instance` definitions).
- tialaramex 4y agoNot just methods, impl defines all associated functions for a type, and Rust automatically allows you to call any associated function as a method if its first argument is some form of "self". If you've got a Cat named puss, the call puss.meow() is effectively shorthand for something like Cat::meow(&puss) where that first parameter was the &self parameter to your "method". Because this is namespaced, there's no problem if your Cat type has this meow() method and a Trait (say, AnimalNoises) it implements also has a meow() function, Rust knows those are different functions and the confusion only arises for a human reader, and only in code that actually wants to call one of the two identically named functions. AnimalNoises::meow(&puss) and Cat::meow(&puss) are distinct, but writing thing.meow() requires inspecting other nearby code to discover whether from context this code knows thing is a Cat or just wants to make AnimalNoises. Where this might be confusing you should write AnimalNoises::meow(&thing) to make your intention clear to humans, and have it checked by the compiler. Only the type's author gets to implement it, and only once (the standard library and especially core are special) so there's an essential distinction between SomeType::function() which was necessarily provided by the SomeType author, and just third party code that works with this type.
- zozbot234 4y agoThere can be additional differences in call syntax due to Deref support, which can delegate methods from a "child" to a "parent" type. For example, if we have puss: Rc<Cat> then puss.clone(); will implicitly call Cat::clone and return a new owned Cat (which can add overhead and is not zero cost) , whilst Rc::clone(puss) will simply create a new Rc reference to the same Cat object.
- tialaramex 4y ago> For example, if we have puss: Rc<Cat> then puss.clone(); will implicitly call Cat::clone [Edited, this used to suggest it's a typo, but probably it's just a different way to think about what's happening, so I removed this claim]. There almost certainly isn't a Cat::clone and in fact what's happening is that Clone is in the prelude, so this is: Clone::clone(&puss) [edited to add] Which is really even: <Cat as Clone>::clone(&puss) and because Rc is a Smart Pointer it implements DeRef and so that's ultimately: <Cat as Clone>::clone(<Rc as Deref>::deref(&puss)) Definitely understandable that people want to write puss.clone() instead. By the way, misfortunate::Multiplicity demonstrates Deref and DerefMut nicely, providing a type which has two things inside it but references to it act like one thing when being mutated and like the other when merely referenced... Not something for absolute beginners, but worth seeing to build correct intuitions (and to underscore Rust's admonition not to implement Deref and DerefMut if you aren't a smart pointer -- misfortunate is like Jackass, this is for entertainment and not to be attempted in your real Rust projects).
- rhodysurf 4y agoExtensions in swift feel mostly the same to me, except you can define them on any type you want and not just types or traits your namespace defines