6 ms·
I think the easiest way to understand it is this: Suppose you have a concrete type like Vec<i32> Regular generics enable you to make the contained type g
by nicoburns 4y ago
I think the easiest way to understand it is this:
Suppose you have a concrete type like
Vec<i32>
Regular generics enable you to make the contained type generic, so you have:
Vec<T>
where T can be i32, u32, String, etc. GATs allow you to make the container generic. So you can have:
T<i32>
where T might be Vec, Option, Box, etc.
- aarobot 4y agoAwesome example.
- fallat 4y agoTHIS is literally the best explanation. My god people have forgotten how to explain anything anymore. Thank you.
- agluszak 4y agoIt is easy to understand because it is an oversimplification :)
- jstx1 4y agoWhich part is inaccurate/incomplete?
- GolDDranks 4y agoThe part that says `T<i32>`. GATs don't allow you to do that, not directly. GATs allow you, as said by Boats in https://news.ycombinator.com/item?id=33506540 https://news.ycombinator.com/item?id=33506540, have a generic type as an associated type, nothing less, nothing more. If you want to express `T<i32>`, GATs _enables_ you to do that as a kind of a distorted encoding, but it's not as simple as https://news.ycombinator.com/item?id=33505810 https://news.ycombinator.com/item?id=33505810 makes it seem.
- howinteresting 4y agoBring able to abstract over Rc/RefCell and Arc/Mutex with marker types seems pretty useful. It's not directly HKT but it enables use cases that would otherwise be supported by HKT.
- dllthomas 4y agoYes, but that doesn't make it somehow accurate to explain HKT and pretend you're explaining GAT...
- howinteresting 4y agoThat is definitely true.
- gpderetta 4y agoThe Associated bit of GAT I guess.
- philzook 4y agoWhat you're describing sounds to me like higher kinded types, which are of some relationship to GATs (GATs enable a better encoding of higher kinded types as I understand it), but are not GATs. https://docs.rs/higher/latest/higher/ https://docs.rs/higher/latest/higher/
- gunapologist99 4y ago> as I understand it You could be 100% right (I have no idea, but it sounds reasonable), but this entire question really hits home that Rust has tons of basically incomprehensible design features. The worst part about features like this are that a few smart people will actually use them (whether because they're powerful features, or just because they feel powerful when using them), and then render their code incomprehensible to the mere mortals who have to support their code in the future. The KISS principle (https://en.wikipedia.org//wiki/KISS_principle https://en.wikipedia.org//wiki/KISS_principle) is sometimes ignored because people don't want to be stupid, and why wouldn't you want to use a new toy(tool) once you've figured it out?
- kibwen 4y agoThis is quite uncharitable. Rust's features aren't there for no reason, they're there to address the hard problems of how to achieve C++-level performance while providing the level of abstraction that modern developers expect and remaining totally type-safe. Furthermore, the amount of hand-wringing over this feature is disproportionate to its actual impact. It feels like people see "Haskell" mentioned in the same breath and immediately lose all sense of reason. This feature is not basically incomprehensible, it's a straightforward addition that allows generics to be used with associated types, both of which are features that already exist in the language. If you're asking yourself, "when would I ever need to use these?", this answer is that you may never find call to use these. Traits are mechanisms for creating abstractions, which are mostly relevant to library authors. If you're not a library author, you may never have a good reason to write a trait. Even for people who are writing traits, they may have no reason to ever use associated types. And even for people who are writing traits with associated types, they may have no reason to ever want to use generics with those associated types. However, all of these features are extremely useful for the people consuming libraries, and far from making Rust code more complicated, from what I've seen so far it makes Rust code in the wild less complicated.
- brap 4y agoThanks, this was much easier to understand than the original article. What will I use this for? Usually for the “T” to be useful it needs to have some interface. In Java I’d just use Collection<Integer> or something more abstract.
- mrkeen 4y agoT keeps its type info statically. So if you put a Set in, you can get a Set out. Casting to Collection loses the static type info, so you couldn't write foo(bar(set)) if bar returned a Collection but foo accepted a Set.
- orblivion 4y agoI forget what exactly a GADT is (even though I've used Haskell a bit before). But just going by the linked example from Reddit, you could make a generic `map` function that worked on any container type. You'd have to implement the map function separately for each type. But then you could make a bunch of utility functions that you'd implement once that use the generic `map` under the hood, and all of those container types would be able to use those utility functions. Not a Rust guy but I think that's the idea.
- kibwen 4y agoJust so that we're clear on acronyms for everyone out there, "GADT" is a computer science term for "generalized algebraic data type", which has no relation to "GAT", which is just Rust terminology for generics in associated types (even in Rust, I doubt that anyone will bother to refer to "GAT" in the coming years, rather than just lumping them in with the concept of associated types in general; there's really no need to teach them separately).
- ghostwriter 4y ago> you could make a generic `map` function that worked on any container type. not only container types, it can be any type that has a consistent context of evaluation for the final value being calculated: "doing async IO", "doing optional presence", "doing potentially erroneous extraction", and so on. In that sense, "doing multiplicity of values" is the context expressing a container type you mentioned as an example.
- inatreecrown2 4y agothis sounds almost too easy to understand, will have to check with the documentation. (thank you!)
- insanitybit 4y agoI think 90% of the reason why people have a hard time with GAT is because there aren't a ton of use cases. From what I can tell, GAT is quite simple - it is just like all other Rust generics except that now the generic can be in a new place. Rust has made it years without needing this (granted, a few things have been less than ideal because of it) because, for the most part, people have not needed to reach for this type of abstraction. But it's really just "Generics in a new place". Personally, I've accidentally written the GAT syntax years before I ever heard the term GAT because I thought a generic could go there.
- Jweb_Guru 4y agoIt's needed for a lot of features people desperately want. Async functions in traits, closures that return futures where you need to run the future in a loop, and array indexing that doesn't necessarily return a reference, are three examples of things that essentially need GATs in order to be implemented without allocating. You may not feel like you missed it but not having that leads to a ton of ugly workarounds in Rust code. Also, in a lot of cases where people would otherwise use GATs, people instead work around them by making traits generic and have super complicated towers of generic types, you've probably seen interfaces like this when using hyper for instance. GATs would simplify most of those interfaces.
- insanitybit 4y agoThe vast majority of users do not desperately want async functions in traits, they just use async_trait and go "it'll be cool when GATs are done". Besides, no one is going to use GAT for async traits, that will be done for them by the compiler. Obviously there are use cases for GAT, what I'm saying is that they're going to be in very generic library code, which I don't think most users are writing. For libraries like Hyper, which prioritize being extremely generic (it's split into a ton of reusable crates), which aims to serve as a very low level set of generic primitives for HTTP, yes it will come up. Hyper is a great example of a use case that 99.99% of developers are not going to be able to relate to because they aren't building a set of completely generic http primitives. It's an important use case, it's just not relatable.
- howinteresting 4y agoNote that this isn't directly what GATs are, but you can use marker types to achieve this effect.
- dllthomas 4y agoThe ability to just use T for Vec, Box, etc, anywhere you might want to is "higher kinded types" - GATs only allow it specifically for "associated types" on a trait.
- johnmc408 4y agoawesome and simple!!!