4 ms·
May I ask what you don’t like about traits (and perhaps insight on what the author meant)? Being a relative rust noob compared to other languages, I always fel
by wuiheerfoj 3y ago
May I ask what you don’t like about traits (and perhaps insight on what the author meant)?
Being a relative rust noob compared to other languages, I always felt traits were a super power when compared to eg interfaces in Java/C++ and flexible but with useful constraints compared to the structural typing nature of Typescript interfaces
- nyanpasu64 3y agoImporting a trait into scope can silently materialize methods on other types, with no syntax at the method call site pointing to which import statement created the methods, requiring you to ask the compiler/IDE. This can also mean that removing a use statement with no references to the type being used in the entire rest of the source file, can make code suddenly stop compiling. I've worked around this by strictly confining "specialized" traits (like std::io::Write or std::fmt::Write, why are there two Writes?!) to the beginning of a single function, but I'm lazy and put "general" traits like std::borrow::Borrow and std::str::FromStr at the top of my file. Which types grow new trait methods is dependent on trait implementations, which can be generic and apply to an unbounded number of types, based on complex matching rules, and figuring out requires reading every impl of that trait to see if any match a given type, or asking the compiler/IDE. I want to explore languages which explicitly select a trait implementation at the call site (like a Heap<int, int_greater> type which uses int_greater::cmp() to implement a min/max heap), or naming the trait (but not picking an impl) at the trait method call site (like Write::write_all(stream, "hello world") or (stream as Write).write_all("hello world")). I think Zig takes a similar direction.
- zozbot234 3y agoYou can use universal function call syntax in Rust: <Type<TyArg> as Trait>::trait_fn(self_arg, fn_arg1, fn_arg2);
- glandium 3y agoThere's worse. When your trait adds function foo and your code does obj.foo(), if the underlying type later adds a foo method, compilation breaks. This is very common with traits that usefully add useful methods that are missing in libstd... which break when said method is finally added there.
- Gwypaas 3y agoI ran into this case yesterday, for some cases there are warnings now. In this case I used ".div_ceil(...)" from from the Num [0] crate. (some_integer).div_ceil(&2) ^^^^^^^^ = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919> = help: call with fully qualified syntax `num::Integer::div_ceil(...)` to keep using the current method = note: `#[warn(unstable_name_collisions)]` on by default [0]: https://crates.io/crates/num https://crates.io/crates/num
- sanxiyn 3y agoIn a trait-like system (including Java interface), there can be only one implementation of a trait for a type. That's why it is global, unlike ML module-like systems. Global is another word for anti-modular. For example, in the real world, there are multiple ways to order strings (called collation), but since there can be only one implementation of (String, Ord) type-trait pair, one ordering is canonical. That may be bearable, but having canonical (String, Hash) implementation is not. What if you want to use (say) faster CityHash instead of canonical MurmurHash? So Rust resorts to things like BuildHasher, to get back multiple implementations. Because it is global/anti-modular, it interferes with separate compilation, and it is one of reasons why Rust is slow to compile. Then why would one use trait instead of module? Since there can be multiple implementations in module, you need to specify. So module is more verbose. In my (and Graydon's) opinion, a bit more verbosity is worth it for modularity, but many people disagreed. This is another theme: Graydon is okay with verbosity, boilerplate, and being bureaucratic. In my (and Graydon's) opinion, programming is work that is secretarial, not artistic, so it is unimportant whether code is ugly or not. You may think current Rust is ugly, but no, it is the way it is because lots of people really cared about Rust code being pretty. If Graydon was a BDFL, Rust would be even more ugly, and in my opinion, as a result, would be a better programming language.
- wuiheerfoj 3y agoThanks for this - the sort example made a lot of sense to me. I thought it was possible to parameterise with specific trait implementations for such a case though I haven’t used it much with I could be misunderstanding.