Live data from Hacker News

Rust: “Explain GATs Like I'm 5 Years Old”

old.reddit.com

121–130 of 193 posts

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#121

The top Reddit example is tremendous. I'm passed being a Rust beginner, but I have a note to the Rust community: Your official examples are overcomplicated and bad and you should also feel a little bad. Stick to things like apple, orange, pear and you'll see much easier adoption than if you go with something like LendingIterator! Through the GAT process all I have seen is the same hyper-specific example used that con…

I think this is a failure of messaging rather than a failure of example-writing. Despite all the hullabaloo, GATs are not a "feature", they're just the lifting of an arbitrary restriction that used to exist in the typechecker. There doesn't need to be a section on GATs in any Rust book, for example. It's just generics in associated types. The examples you've seen like LendingIterator are not intended to be pedagogical, they're intended to showcase some specific cool things that people (who are presumed to already know Rust) will now be able to do, and preview things that might someday find their way into the stdlib as a result of this new ability.

For sure, if people want to learn how to use generics in associated types, then there can be examples catering to those users. But I think that framing this as a "feature" makes people feel like they need to go out of their way to "learn" them, when in reality users will either try to use them naturally (as a result of prior knowledge about generics and traits) and it will "just work" and they'll never think twice about it, or they'll never try to use them because they see no need to based on what they're trying to write.

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#122
post #80

Earlier quoted context omitted.

Aren't GATs equivalent to nested template classes? I.e. they are really orthogonal to concepts.

Might be a bit of job deformation, knowing C++ since 1993, and I still need to get myself used to those patterns. Maybe I should delve again into GADTs in OCaml, before having a second look.

GATs are completely unrelated to GADTs.

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#123

Earlier quoted context omitted.

The solution to this is to have two examples: Beginner and Practical/Advanced

I think the point is that even for beginners these examples are dumb. If you want to explain OOP and inheritance you can use simple but realistic examples, like `class Shape { fn draw() }`, `class Rectangle extends Shape`, `class Circle extends Shape`, rather than `class Dog extends Animal` or some dumb stuff like that.

Bingo

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#124
Although the "LendingIterator" example is apparently done to death, I'm going to try to explain it in a way that is actually appropriate for "ELI5".

In Rust, there are many different ways to have a list of things that come one after another. But sometimes we want to write some code that doesn't care about the details like whether the list is a list of words, or a list of numbers, it just cares about the fact that there are a list of things in order.

Right now, we call these general lists of things in order "Iterators", with code like this:

    trait Iterator {
        type Item;
        fn next(&mut self) -> Self::Item;
    }

This tells us what an "Iterator" means. "Item" is the type of thing that is in the list, for example it could be "number" or "word". "next" is a function, which means it is something we can do. When we do the "next" function, we get the next thing in the list. So if we keep doing the "next" function over and over, we can get everything in the Iterator one by one.

However, sometimes we want to have more complicated lists, where the "next" function doesn't actually get us the next thing in the list, it just tells us the address of the next thing inside the computer. We would write this code like this:

    trait StaticIterator {
        type Item;
        fn next(&mut self) -> &'static Self::Item;
    }
However, this requires the thing in the list to always be at the address (that's what "&'static" means). But a lot of the time the thing stays at the address while we are looking at the list, and later it will go away.

We could write code saying that the things only have to be at the address for a certain period of time. It would look like this:

    trait ReferenceIterator {
        type Item;
        fn next(&mut self) -> &'a Self::Item;
    }
This solves that problem, because now we are saying the address only has to have the thing at it for the the time period "a" (we call "a" the lifetime, because it tells us how long the things will live at the address). The problem is, that when we write "Iterator" we have to decide up front what the lifetime will be. So we can't use the same code for lists with different lifetimes, we would need to write the same code twice, once for each lifetime.

This problem is what GATs help us with. GATs are a way to say that we are going to have a list of addresses, where the lifetimes could be different for each list. We would write the code like this:

    trait LendingIterator {
        type Item where Self: 'a;
        fn next(&mut self) -> Self::Item; 
    }

This allows us to write code which doesn't decide up front what the lifetime of the addresses will be. Instead, the same code can happily work with lists of addresses with any lifetime. GATs may seem scary at first, but as you can see, they are not doing anything fancy, just allowing us to do what we should be able to do: write one piece of code that can work with lists of addresses with different lifetimes.

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#125

Earlier quoted context omitted.

I think the easiest way to understand it is this: Suppose you have a concrete type like Vec Regular generics enable you to make the contained type generic, so you have: Vec where T can be i32, u32, String, etc. GATs allow you to make the container generic. So you can have: T where T might be Vec, Option, Box, etc.

this sounds almost too easy to understand, will have to check with the documentation. (thank you!)

I 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.

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#126
This comment here serves as a gravestone for a long form, well written (I think) explanation of GATs that I thought was actually ELI5 (unlike every other ELI5 response which always immediately starts dropping tons of jargon), which Firefox lost when somehow it randomly activated the back button ;_;.

I could potentially rewrite it if anyone was interested, but I am under no illusions that's likely ;)

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#127

Is there any way to use GATs to achieve a particular use case of ah-hoc/anonymous enums[0]? Say if library L1 returns enum A|B, L2 operates on enum A|B, and main wants to pass enum A|B from L1 to L2, with the kicker being A, B are concrete in main. I'm not interested in distinguishing between multiple appearances of the same type as in the RFC example, so rather like: let foo: (~str|int) = (_|666); match foo { (s: st…

You might be interested in Rust's either crate (not built-in): https://docs.rs/either/latest/either/

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#128

The top Reddit example is tremendous. I'm passed being a Rust beginner, but I have a note to the Rust community: Your official examples are overcomplicated and bad and you should also feel a little bad. Stick to things like apple, orange, pear and you'll see much easier adoption than if you go with something like LendingIterator! Through the GAT process all I have seen is the same hyper-specific example used that con…

The example is indeed very good, but I think it is more about faking HKT with GAT and I'm not sure that was the primary motivation for GAT in rust.

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#129
post #82

I'm filing this one along with Monads and Haskell as programming concepts that I'll never understand. Rust is my favorite language, but that explanation, lauded directly below it as This is personally the easiest to understand example I've seen of GATs. , was incomprehensible.

Wait. Why are Monads complicated? Yes the math definition is complicated, but so is math definition of number 1 in set theory You have a Rust-like enum that contains data like Option or Maybe, you want to abstract over it. There you have a rudimentary Monad.

No, monad is more complicated than that. There is a specific method that it has to have, which does not make sense on all types, and can also have more than one sensible definition for a type. "You want to abstract over it" gets you to a "trait", not a "monad".

Re: Rust: “Explain GATs Like I'm 5 Years Old”

#130

I seriously doubt a 5 year old can understand this explanation.

It's arguably in the category of "pet peeve" more than anything else, but I really hate the ELI5 meme and suspect most people asking for it and/or trying to provide explanations that fit it have never had a five-year-old. Unless your target five year old is a five year old Terence Tao, and honestly even then, most of the time these are terrible.

ELI12 would make a lot more sense; old enough to have had enough life experience to hang some of these explanations off of, young enough to need simple explanations.

Post reply on HN