So now we can also get a MapFamily trait, which is implemented for HashMap and BTreeMap, and I can make my types generic over the map implementation :)
Great example! I don't really like the MapFamily name, though -- why not just Map? That's what Scala does: Map is the generic interface which is implemented by HashMap, TreeMap, and others.
@@ClearerThanMud Yeah, I don't like the family name in general. I also wouldn't implement it using new marker types, but just implement that trait on maps directly. I think, this also hasn't been possible before because of lifetime issues, which could be solved by using generic lifetimes on associated types.
@@ClearerThanMud Your Map example clarifies this video. Since the beginning of the video I ask "What is the purpose of families?", now I understood. What Scala does is what Java does. Chris needs to remake this video as Pointer to clearly explain the purpose, otherwise it is hard to assign a meaning to these families.
still don't get it. the example is very abstract, more proper approach would be to show a practical problem and a minimal solution to this problem which makes use of GATs. also don't get why such a feature takes 6 years to make it to stable.
Same, when I started learning rust, I already know when to use generics on trait, and when to not use generics on trait and opt in for associated types Now I just don't see the purpose of having generic associated types in the language My best guess would be now you can have everything?
To get the jargon out of the way: GATs are a step towards implementing Higher-Kinded Types (or Higher-Order/Rank types). If you think of generics as a function that takes a type, and outputs a type, for example: struct Two(T, T) You can give it a type T, for example, i32, and it'll give you a type: Two(i32, i32). You cannot pass this function "Two", to anything, you cannot for example make a `Vec`, you have to have an actual type there, such as `Vec`. With HKTs, this restriction is essentially lifted, and you can have a type that takes `Two` as an actual argument (not Vec though). Some examples where this might be useful: - Algorithms that are generic over data structures. - Having a uniform way of talking about smart pointers. - Policy types. In reality, most code won't need to ever use these, and for many of these scenarios, we have good alternatives (like the Iterator and Extend traits), and that makes it very difficult to showcase its value. They're a little bit like "template template parameters" in C++ (that's the real term), which are niche, and rarely used, but sometimes, they're the best solution.
once again, such an awesome video! it is amazing how you're able to break some of these really complex topics down into simpler, more concrete examples! this is extremely helpful, thank you!
"... but also the things that people now figure out that they are able to do because they are able to experiment on the stable rust release" The rust team has asked people to experiment with this on nightly for over a year already. Partly to iron out kinks, but also to help expand the awareness of what GATs are capable of. Of course, many more will do so now that it's in stable, but the optimal situation would be if everyone with an interest in this feature had been doing it since August last year. I'm not one to talk, since I first heard about this yesterday. But still. Just another example that else being equal, the rust team likes people to use nightly in their everyday development.
I can imagine using this for simulation objects that need to swap environments and change behavior based on environment. It’s not necessary, because an ECS can enable that sort of dynamism, but this unlocks a more “encapsulated” approach to dynamic behavior modification.
So... What is the meaningful advantage over an ECS? More encapsulated might be useful, and also, if it's for game programming, let's say, does it matter how encapsulated something is or isn't? Security issues may be a concern depending on the nature of the gane, but I don't have a concrete scenario / use case in mind for one approach over the other.
So, I’m learning and writing in Rust, but still working on learning some Haskell in the side as well. I haven’t come across GADTs in haskell yet, but have seen the term before. Well, this past week I’ve been attempting to figure out how Haskellers think about organizing the entirety of their app code when they have to do everything in a monad. Well, monads don’t compose so there’s a variety of ways to get around this (Monad transformer stacks, MTL, Free monads, Tagless final). I don’t understand the implications of all of the approaches just yet, but while watching your explanation of GADTs earlier today, the idea that you could have an array of effects and each of the effects implemented in a similar way as your Foo example. I believe that’s the approach that he implemented below in this video at the 8:30 mark. That syntax at the top of the screen that starts with the data keyword is a GADT in Haskell. ua-cam.com/video/BUoYKBLOOrE/v-deo.html
I'm not sure if you meant it, but GADTs are different from GATs. GADT is Generalized Algebraic Data Type, while a GAT is a Generic Associated Type. GATs are what stabilized in Rust 1.65, while GADTs are mostly a Haskell concept often used for placing additional restrictions on domain specific languages.
Sometimes all we need to do in order to learn a language is to take time and experiment like a fool over and over to understand complex concepts. Atleast that's how I learned these things.
Your channel is great, but as a hearing imparied person who uses captions all the time, having captions labeled as normal captions but are clearly just auto-generated seems kinda manipulative (kinda too strong a word, couldn't think of a lighter one that carried a similar meaning)
I don't know what to say if you think I'm being manipulative :/ I do the best I can do in the time I have to do it. Yes the captions are autogenerated as a first pass. I try to edit them after that depending on how much time I have to do so, similar to how much time I can use to edit the videos. There's no button in the UA-cam backend that I can click (that I know of) that would signify "these were autogenerated and this is how much time I had to edit them this time". I don't have a backlog of videos at the moment, so I can't pay to send them off to someone else to caption in time to ship them. I hear you that the captions aren't as good as you need them to be. I'm doing the best I can at the moment and I do make them better over time as I can.
@@chrisbiscardi yeah manipulative wasn't a good word. I thought they were identical to the auto captions which made me feel off, but I guess I was wrong about that, so I apologize.
not really. The pipe operator in TypeScript is like saying "this value can be one of these three types" because in JS/TS you can pass anything anywhere. You could use the pipe operator to write a function that accepted a value that was a string or a number, then do a runtime check to determine which it was and change the behavior of the function based on that runtime check. In Rust if you use a generic, you also specify what functionality that generic needs to implement, so you know at compile time what you can do with it. GATs are specifically the ability to use generics and lifetimes in the associated type for a trait. So traits already had associated types, but now we can use generics in them instead of concrete types , and lifetimes allows us to apply borrowing in the same way.
Associated type is logically similar to conditional type in Typescript, and GAT enables associated type to be generic, which is a restriction conditional type doesn't have in the first place.
So now we can also get a MapFamily trait, which is implemented for HashMap and BTreeMap, and I can make my types generic over the map implementation :)
Great example! I don't really like the MapFamily name, though -- why not just Map? That's what Scala does: Map is the generic interface which is implemented by HashMap, TreeMap, and others.
@@ClearerThanMud Yeah, I don't like the family name in general. I also wouldn't implement it using new marker types, but just implement that trait on maps directly. I think, this also hasn't been possible before because of lifetime issues, which could be solved by using generic lifetimes on associated types.
@@ClearerThanMud Your Map example clarifies this video. Since the beginning of the video I ask "What is the purpose of families?", now I understood. What Scala does is what Java does. Chris needs to remake this video as Pointer to clearly explain the purpose, otherwise it is hard to assign a meaning to these families.
still don't get it. the example is very abstract, more proper approach would be to show a practical problem and a minimal solution to this problem which makes use of GATs. also don't get why such a feature takes 6 years to make it to stable.
I also did not gain much from this. My biggest question is what is the deal? What really took 6 years?
From what I get is, that you couldn't have a *generic* associated type - so you couldn't have as part of type in the PointerFamily trait
Same, when I started learning rust, I already know when to use generics on trait, and when to not use generics on trait and opt in for associated types
Now I just don't see the purpose of having generic associated types in the language
My best guess would be now you can have everything?
@@brdrnda3805 I also got that, but why? Is not it trivial to implement such a feature in the compiler?
To get the jargon out of the way: GATs are a step towards implementing Higher-Kinded Types (or Higher-Order/Rank types).
If you think of generics as a function that takes a type, and outputs a type, for example:
struct Two(T, T)
You can give it a type T, for example, i32, and it'll give you a type: Two(i32, i32).
You cannot pass this function "Two", to anything, you cannot for example make a `Vec`, you have to have an actual type there, such as `Vec`.
With HKTs, this restriction is essentially lifted, and you can have a type that takes `Two` as an actual argument (not Vec though).
Some examples where this might be useful:
- Algorithms that are generic over data structures.
- Having a uniform way of talking about smart pointers.
- Policy types.
In reality, most code won't need to ever use these, and for many of these scenarios, we have good alternatives (like the Iterator and Extend traits), and that makes it very difficult to showcase its value.
They're a little bit like "template template parameters" in C++ (that's the real term), which are niche, and rarely used, but sometimes, they're the best solution.
Thank you. My team has been waiting on GATs for our implementation of our new specification.
Thank you for this explanation! Had a hard time wrapping my head around the concept when reading the RFC, but this made everything much more clear!
once again, such an awesome video! it is amazing how you're able to break some of these really complex topics down into simpler, more concrete examples! this is extremely helpful, thank you!
"... but also the things that people now figure out that they are able to do because they are able to experiment on the stable rust release" The rust team has asked people to experiment with this on nightly for over a year already. Partly to iron out kinks, but also to help expand the awareness of what GATs are capable of. Of course, many more will do so now that it's in stable, but the optimal situation would be if everyone with an interest in this feature had been doing it since August last year.
I'm not one to talk, since I first heard about this yesterday. But still. Just another example that else being equal, the rust team likes people to use nightly in their everyday development.
yep, totally agreed. People using nightly greatly helps features like this and it's encouraged that people do so as these sorts of features develop.
I can imagine using this for simulation objects that need to swap environments and change behavior based on environment.
It’s not necessary, because an ECS can enable that sort of dynamism, but this unlocks a more “encapsulated” approach to dynamic behavior modification.
So... What is the meaningful advantage over an ECS? More encapsulated might be useful, and also, if it's for game programming, let's say, does it matter how encapsulated something is or isn't? Security issues may be a concern depending on the nature of the gane, but I don't have a concrete scenario / use case in mind for one approach over the other.
Thanks for the video. Now I just need to play around with it and see when it would be useful.
So, I’m learning and writing in Rust, but still working on learning some Haskell in the side as well.
I haven’t come across GADTs in haskell yet, but have seen the term before.
Well, this past week I’ve been attempting to figure out how Haskellers think about organizing the entirety of their app code when they have to do everything in a monad.
Well, monads don’t compose so there’s a variety of ways to get around this (Monad transformer stacks, MTL, Free monads, Tagless final).
I don’t understand the implications of all of the approaches just yet, but while watching your explanation of GADTs earlier today, the idea that you could have an array of effects and each of the effects implemented in a similar way as your Foo example.
I believe that’s the approach that he implemented below in this video at the 8:30 mark.
That syntax at the top of the screen that starts with the data keyword is a GADT in Haskell.
ua-cam.com/video/BUoYKBLOOrE/v-deo.html
here's another mind-bender for you: GATs aren't the same as GADTs.
Generic Associated Types vs Generalized Algebraic Data Types
I’VE NEEDED GADTs SO BAD AND DIDN’T REALIZE IT UNTIL SEEING THEM NOW
I'm not sure if you meant it, but GADTs are different from GATs. GADT is Generalized Algebraic Data Type, while a GAT is a Generic Associated Type. GATs are what stabilized in Rust 1.65, while GADTs are mostly a Haskell concept often used for placing additional restrictions on domain specific languages.
@@chrisbiscardi Probably just a typo on OP's part, but I've seen Haskell code using GADT to emulate TypeFamily, which is what the video showcases too.
As always, interesting and straight into the point.
I absolutely love your videos
Sometimes all we need to do in order to learn a language is to take time and experiment like a fool over and over to understand complex concepts. Atleast that's how I learned these things.
Nice explanation, thanks for sharing
Your channel is great, but as a hearing imparied person who uses captions all the time, having captions labeled as normal captions but are clearly just auto-generated seems kinda manipulative (kinda too strong a word, couldn't think of a lighter one that carried a similar meaning)
I don't know what to say if you think I'm being manipulative :/ I do the best I can do in the time I have to do it. Yes the captions are autogenerated as a first pass. I try to edit them after that depending on how much time I have to do so, similar to how much time I can use to edit the videos. There's no button in the UA-cam backend that I can click (that I know of) that would signify "these were autogenerated and this is how much time I had to edit them this time". I don't have a backlog of videos at the moment, so I can't pay to send them off to someone else to caption in time to ship them.
I hear you that the captions aren't as good as you need them to be. I'm doing the best I can at the moment and I do make them better over time as I can.
@@chrisbiscardi yeah manipulative wasn't a good word. I thought they were identical to the auto captions which made me feel off, but I guess I was wrong about that, so I apologize.
So it's kind of like typescript's pipe?
not really. The pipe operator in TypeScript is like saying "this value can be one of these three types" because in JS/TS you can pass anything anywhere. You could use the pipe operator to write a function that accepted a value that was a string or a number, then do a runtime check to determine which it was and change the behavior of the function based on that runtime check.
In Rust if you use a generic, you also specify what functionality that generic needs to implement, so you know at compile time what you can do with it.
GATs are specifically the ability to use generics and lifetimes in the associated type for a trait. So traits already had associated types, but now we can use generics in them instead of concrete types , and lifetimes allows us to apply borrowing in the same way.
Associated type is logically similar to conditional type in Typescript, and GAT enables associated type to be generic, which is a restriction conditional type doesn't have in the first place.