8 ms·
Rust stabilizes generic associated types
- celeritascelery 4y agoI have been waiting for this feature for forever! I am so excited to have it stabilize (hopefully doesn’t get reverted). This will cut down on so much boiler plate in traits and enable new design patterns. This moves us one step closer to true HKT’s.
- cercatrova 4y agoI remember a Rust team member (perhaps several) saying that they don't want full higher kinded types in Rust, as GATs (I'm paraphrasing here) should give most of the functionality for a smaller footprint. I'm not sure how true that is though. What are some use cases in your view for HKTs?
- lmm 4y agoNot the person you replied to but: Writing combinators that work generically over Fn/FnMut/FnOnce (for a very simple case, try writing the "compose" function - currently you have to write all three implementations separately even though they're identical). Writing code that works polymorphically between sync and async - this solves the "function colouring" problem without having to give up precise control of where yields happen. Writing data structure traversals (e.g. a tree walker/visitor) that can handle some kind of extra "context" in a generic way (e.g. updating a state, or making a database call, or indeed making an async call).
- cercatrova 4y agoDo you think the keyword generics initiative will solve these issues? https://blog.rust-lang.org/inside-rust/2022/07/27/keyword-generics.html https://blog.rust-lang.org/inside-rust/2022/07/27/keyword-ge...
- lmm 4y agoIf they take the time and effort to build a consistent underlying model, yes (though I think the only proven way to do that would be to implement proper higher-kinded types and then turn keywords like async into syntax sugar for those). If they just add a bunch of ad-hoc cases for the keywords that are visibly causing problems then they'll probably make the issue worse rather than better. Given Rust's history of missed opportunities with this kind of thing (NLL, try/?, async), I'm not particularly hopeful.
- cercatrova 4y ago> Given Rust's history of missed opportunities with this kind of thing (NLL, try/?, async) What happened with these? I'm out of the loop.
- lmm 4y agoThey're all addressing problems that would be solved elegantly with full higher-kinded types, but Rust has opted for narrow ad-hoc approaches instead.
- cercatrova 4y agoYou should write about this somewhere, or even on their GitHub RFCs, as it seems from what I've read that they don't want to have HKTs due to how it interacts with the borrow system (poorly, apparently) as it's not as easy as with Haskell or OCaml which are garbage collected.
- lmm 4y agoThey're aware, plenty of people have tried to convince them that full HKTs are what they need and they're wasting their time doing dozens of partial implementaions instead of biting the bullet and doing it properly. They've made their decision that they'd rather do partial incremental work, and I'm not even sure they're wrong (it could be that they'll need the experience of all these different partial approaches in order to figure out how to make their borrow system handle HKT safely). I just hope they'll find a way to migrate all this stuff onto a coherent foundation when they finally do implement full HKT.
- zozbot234 4y agoHKT's ought to be relatively easy to implement as a pattern on top of GAT's, so in that sense the functionality is available. The only immediate drawback is a slightly more complex syntax than what most languages support for HKT's, i.e. you have to express what would be type families in other languages as associated type constructors in Rust. But this is for good reasons as Rust devs have found that associated types seem more idiomatic in the context of a somewhat lower-level language. Other than that, the features are really quite similar. (This 2020 blogpost https://www.fpcomplete.com/blog/monads-gats-nightly-rust/ https://www.fpcomplete.com/blog/monads-gats-nightly-rust/ does a nice job of describing one such pattern, though their choice of Unwrapped and Wrapped<> as identifiers is overly obscure.)
- kibwen 4y agoI'm under the impression that "true" HKTs are incompatible with monomorphization, which means they wouldn't ever happen with Rust. (However, I also don't quite understand why these two concepts are incompatible.)
- Gwypaas 4y agoHere is some history of GATs, from the original author of the RFC and how their sole purpose is to not have to add HKTs. From the collapsed discussion in the OP. https://github.com/rust-lang/rust/pull/96709#issuecomment-1148852889 https://github.com/rust-lang/rust/pull/96709#issuecomment-11...
- turminal 4y agoCan someone summarize what this means for the average rust programmer?
- orangesite 4y agoPrimary benefit for average rust programmer: Less worrying about needing to specify lifetimes when using other people's libraries.
- loeg 4y ago> There are a myriad of potential use cases for GATs. Stabilization unblocks probable future language features (e.g. async functions in traits), potential future standard library features (e.g. a LendingIterator or some form of Iterator with a lifetime generic), and a plethora of user use cases (some of which can be seen just by scrolling through the tracking issue and looking at all the issues linking to it). There are other possible uses, but those two are ones a typical Rust developer may have already run into.
- capableweb 4y agoBest documentation is probably the RFC: https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md https://github.com/rust-lang/rfcs/blob/master/text/1598-gene... > Allow type constructors to be associated with traits. This is an incremental step toward a more general feature commonly called "higher-kinded types," which is often ranked highly as a requested feature by Rust users.
- deleted 4y ago[deleted]
- jstx1 4y agoAnyone else kind of losing the thread of all the programming language abstractions that Rust is stacking on top of each other?
- numeromancer 4y agoIn this case it is the lack of this ability which, when you meet it, is unexpected and unintuitive. Think of this as a design-level bug-fix.
- whatshisface 4y agoGATs are a really straightforward extension of what the language already has. All this means is that now a generic type can take a value as a parameter, for example there could be a generic fixed-length array, which took a length as a parameter. In the past libraries had to hack their way around this by having huge tables of types named like, "N1, N2... N16... N1003", which were passed to generic signatures to indicate to the type system how big something had to be. I don't think this makes the language more confusing, because putting an integer inside of the generics brackets is something that previously you might try to do, if you didn't know it wasn't allowed. In fact, I would go so far as to say that this is a compiler feature, rather than a language feature, because it fills in a semantic hole that already existed in the way Rust programmers thought about Rust types. :-)
- deleted 4y ago[deleted]
- petrosagg 4y agoThe feature you're referring to is const generics which is different than generic associated types (GATs) which is the feature being stabilized. min_const_generics have been on stable for while
- deleted 4y ago[deleted]
- deleted 4y ago
- Sytten 4y agoOne step closer to native async trait support! This is really a good day for rust.
- super_flanker 4y agoWhat kind of ergonomic benefit would this bring to an average rust developer who doesn't go into the depth of rust traits/type systems and just use libraries made by other smart people to develop some web service backend?
- masklinn 4y agoLending iterators is the most obvious. Also simplification for library maintainers, and the ability to better abstract over traits (leading to less boxing / dynamic dispatch). So more flexible APIs and more efficient code for the consumer, and simpler library code (which is usually an improvement in reliability and maintainability). https://github.com/rust-lang/rust/pull/96709#issuecomment-1173170243 https://github.com/rust-lang/rust/pull/96709#issuecomment-11... Has an extensive list of libraries wanting to use GATs, with their justifications.
- 0b01 4y agoHere's an underrated application: allowing "view bag" types where one can register a concrete object with its type.
- givemeethekeys 4y agoPardon my beginner question: how soon do updates like this make it into the Rust book?
- dnsco 4y agoA new release is cut every 6 weeks, this was merged so it could make it on the 1.65 release train: https://rust-lang.github.io/rustup/concepts/channels.html https://rust-lang.github.io/rustup/concepts/channels.html
- givemeethekeys 4y agoVery cool! Thank you!
- est31 4y agoIn fact, it's one of the last features that will make it to 1.65 as the branch for 1.65 will soon branch off, and new changes on the master branch will only make it to 1.66.
- carols10cents 4y agoHi! Book author here. I think the other comments were answering when the feature will be available in a stable release. No content has been written for this, and it's not entirely clear to me yet how best to work this into the book. The RFC is probably the best documentation for now.
- givemeethekeys 4y agoGot it! Thanks, much!
- hdjdjyvuv 4y agoThanks for your work! I always recommend this as a well-written programming book.
- carols10cents 4y ago
- davidatbu 4y agoSo I have a question about GATs: since there was a lot of concern about the complexity cost they add, was it not possible to just define traits with generic params (instead of generic associated types, GATs) to achieve everything GATs could? To demonstrate, doesn't something like this work for lending iterators? trait LendingIterator<'a, T> { fn next(&'a mut self) -> Option<&'a T>; } impl<'a, T> LendingIterator<'a, T> for Whatever { fn next(&'a mut self) -> Option<&'a T> { todo!() } } And of course, you'd modify the for loop syntax to desugar appropriately if the the iterator implements LendingIterator.
- xavxav 4y agoAn immediate issue which could be addressed with further complexity is that for loop desugaring is done very early in Rust's compilation pipeline, way before typing is actually performed. This would also be weird in the case that you have a for loop over some generic iterator, the monomorphized code could vary quite a bit based on what trait your type implements.
- retrocat 4y agoAs far as I can tell, this can't actually work, because the return type of `fn next(&'a mut self)` should actually live for some lifetime `'b` that is shorter than `'a`, instead of at least as long as `'a`; mostly because `next` borrows `self` mutably.
- jph 4y agoRust generic associated types are explained on the Rust blog: https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html https://blog.rust-lang.org/2021/08/03/GATs-stabilization-pus... GATs (generic associated types) allow you to define type, lifetime, or const generics on associated types. If you're familiar with languages that have "higher-kinded types", then you could call GATs type constructors on traits.
- ThinkBeat 4y agoCould someone dumb this down for me? ELI5?