3 ms·
I'm hoping people won't go crazy with it. Generics are one of the things that drive me nuts about the Rust ecosystem... it feels like every library in Cargo is
by klodolph 5y ago
I'm hoping people won't go crazy with it. Generics are one of the things that drive me nuts about the Rust ecosystem... it feels like every library in Cargo is based around a bunch of types with a bunch of unnecessary type parameters. Like, if I want to parse command-line arguments.
What I do want is to stop implementing sort.Interface over and over again.
- cle 5y agoAgree, this is my hope. Seeing the same thing play out in other language ecosystems though, I'm just not very optimistic about it.
- masklinn 5y ago> Like, if I want to parse command-line arguments. What command-line parsing libraries have “a bunch of unnecessary type parameters”? Only library I can think of which even has them would be structopt, and that’s not unnecessary, the entire point of the library is to deserialise to a structured type. And of course rust was designed from the ground up to leverage generics, e.g. by design it does not have reflection / RTTI, interactions with variable or foreign types are thus generics based (often, sometimes trait objects will do though they have their own tradeoffs), or it doesn’t have overloading so while not handing all overloading use cases by a long shot it uses conversion traits (aka generics) for “convenience” overloads e.g. foo(string) and foo(path) become foo<T>(_: T) where T: AsRef<Path>.
- klodolph 5y agoYes, Rust was designed from the ground-up to leverage generics, and as a result, the ecosystem is full of generics. There is overuse of generics in Rust. > ...by design it does not have reflection / RTTI,.. I don't think of those as comparable features. Reflection is more or less an alternative way to accomplish many of the same things that you get with macros in Rust. Where you'd see reflection in C# or Go is for something like serializing an object to JSON, and in Rust you'd get some library with a macro to do it for you. The Rust version could still be completely monomorphic, most of the time. RTTI is just std::any. Rust has it. However, 99% of the time, when I'm using dynamic_cast<T>(x) in C++ or switch x := x.(type) in Go, I would have been using an enum in Rust. The convenience overloads for Rust are nice, that's not the overuse I'm talking about. I'm talking about the fact that some library authors seem to avoid &dyn like it were poisonous, even if it makes total sense and would make large chunks of your library monomorphic. There are also minor code size issues that come about because some library authors forget that the convenience overload should probably just call an underlying monomorphic function, especially for cases like AsRef arguments. I am under the assumption here that if you really like generics, you probably like Rust, and vice versa. This is kind of a taste thing, so what is overuse of generics for me (hello, C++'s std::chrono, std::mt19937) might be the bee's knees for you. I did a fair bit of Haskell and C++ before Rust, and as I got more experience with those languages, I used generics less. Monomorphic types are always easier to understand, and they should be preferred.
- masklinn 5y ago> There is overuse of generics in Rust. You made that claim several time, but still provided literally no evidence, just a lot of handwaving and careful avoidance of any sort of concrete point. > I don't think of those as comparable features. > Reflection is more or less an alternative way to accomplish many of the same things that you get with macros in Rust. They go together e.g. where Go uses reflection, Rust uses Derive or manually implemented traits and generic functions working with those traits. JSON is a pretty obvious example there. > I'm talking about the fact that some library authors seem to avoid &dyn like it were poisonous, even if it makes total sense and would make large chunks of your library monomorphic. I would not necessarily disagree with that although I would word it more kindly: since generics always work, they're the default, as a result dynamic dispatch is a fallback when either you must have dynamic dispatch or someone pointed out that the static dispatch was less than optimal (which can be impossible to find out through microbenchmarks). Plus `&dyn` means you're now restricted to borrow-ability, and `Box<dyn>` incurs allocation costs. Generic function skip both concerns.
- klodolph 5y ago> You made that claim several time, but still provided literally no evidence, just a lot of handwaving and careful avoidance of any sort of concrete point. I'm not really interested in arguing that point, just because you asked me to give concrete details doesn't obligate me to provide them or engage in the conversation to a level of detail that would satisfy your request. It's okay to share an opinion without defending it. Part of language ergonomics is that languages provide you with with "escape hatches" to avoid making certain decisions in the design of your system. This might mean that the decisions are made by the callers. Good API design requires figuring out which questions should be answered by your API and which questions should be answered by the caller. Just as an observation... generics are an escape hatch that let you avoid choosing concrete types, and forces your caller to do that for you, and in general, I think library authors use that escape hatch too often. This is not specific to Rust.
- duped 5y agoThe vast majority of the usage of generics in Rust are as replacements for inheritance or dynamic dispatch. It's not very different structurally.