[HN Gopher] Rust stabilizes generic associated types
       ___________________________________________________________________
        
       Rust stabilizes generic associated types
        
       Author : xavxav
       Score  : 112 points
       Date   : 2022-09-13 20:30 UTC (2 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | super_flanker wrote:
       | What 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 wrote:
         | Lending 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-11...
         | Has an extensive list of libraries wanting to use GATs, with
         | their justifications.
        
         | 0b01 wrote:
         | Here's an underrated application: allowing "view bag" types
         | where one can register a concrete object with its type.
        
       | celeritascelery wrote:
       | I 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.
        
         | Gwypaas wrote:
         | Here 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-11...
        
         | cercatrova wrote:
         | I 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?
        
         | kibwen wrote:
         | I'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.)
        
       | givemeethekeys wrote:
       | Pardon my beginner question: how soon do updates like this make
       | it into the Rust book?
        
         | dnsco wrote:
         | A 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
        
           | givemeethekeys wrote:
           | Very cool! Thank you!
        
           | est31 wrote:
           | In 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 wrote:
         | Hi! 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.
        
           | hdjdjyvuv wrote:
        
       | jph wrote:
       | Rust generic associated types are explained on the Rust blog:
       | 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.
        
       | davidatbu wrote:
       | So 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 wrote:
         | An 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.
        
       | turminal wrote:
       | Can someone summarize what this means for the average rust
       | programmer?
        
         | loeg wrote:
         | > 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.
        
         | orangesite wrote:
         | Primary benefit for average rust programmer: Less worrying
         | about needing to specify lifetimes when using other people's
         | libraries.
        
         | capableweb wrote:
         | Best documentation is probably the RFC:
         | 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]
        
       | jstx1 wrote:
       | Anyone else kind of losing the thread of all the programming
       | language abstractions that Rust is stacking on top of each other?
        
         | numeromancer wrote:
         | In 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.
        
         | avgcorrection wrote:
         | Sure.
         | 
         | It seems like a pattern for languages that try to be more
         | pragmatic. Instead of a Big Idea, turtles-upon-turtles approach
         | that would take years to finalize in a form that doesn't
         | invalidate everything that came before it, one goes for an
         | initially good enough approach and then release more and more
         | features which to the insider might seem very holistic but to
         | an outsider (like me) just sound like Static Runtime-Bounded
         | Polyhydral Lambda Cube Type Capabilities and Associates.
        
         | aidanhs wrote:
         | I recently refactored some traits that had a lot of repetitive
         | noise in the generic type parameters (which end up being
         | reflected in function signatures etc). I went about this
         | without really being overly aware of GATs and their status, but
         | the code that I naturally ended up with required enabling them.
         | 
         | So from my point of view, I didn't really _need_ to understand
         | what GATs were bringing - it 's a lifting of restrictions that
         | would have previously felt arbitrary.
        
         | kibwen wrote:
         | Conceptually it's "just" the ability to take one existing
         | concept, generics, and apply it to another existing concept,
         | associated types. Under the hood there's a lot going on to make
         | that work with the type system, and there's some advanced
         | things that this now enables, but as far as a beginner is
         | concerned this is less "a new feature" than "lifting a
         | restriction on an existing feature".
         | 
         | By analogy, imagine a version of C where you can't use a struct
         | as a member of a union. Then, a new version of C comes along
         | letting you use structs in unions. We could call that a new
         | feature, "struct-in-unions"... or we could just call it lifting
         | a restriction on an existing feature. It's entirely natural to
         | want to use structs with unions, and it's probably what a
         | learner of the language intuitively expects should be possible.
         | Likewise, a learner of Rust probably expects that any type can
         | be used as an associated type, and before today that wasn't
         | true, and after today that is true.
        
           | capableweb wrote:
           | > Conceptually it's "just" the ability to take one existing
           | concept, X, and apply it to another existing concept, Y.
           | 
           | Yes, precisely. This is the literally what parent was talking
           | about, "programming language abstractions [...] stacking on
           | top of each other"
        
             | necubi wrote:
             | As opposed to creating completely different ways of doing
             | things from the existing patterns?
             | 
             | The parent was echoing the common complaint (exclusively
             | from people who don't actually use rust, in my experience)
             | that rust is getting "too many features."
             | 
             | But as others in this thread has pointed out, features like
             | GATs actually make the language simpler, because they're
             | removing weird (and to a new user, unexpected) restrictions
             | on existing features. This will then unblock removing other
             | surprising restrictions, like the inability to use async
             | functions in traits.
             | 
             | Rust takes the philosophy that it's better to do hard work
             | in the compiler in order to make the language simpler and
             | easier for users. That's what's happening here.
        
             | [deleted]
        
             | stusmall wrote:
             | Try thinking of it less as a new abstraction and more of
             | removing a restriction from a previous abstraction. It is
             | pretty easy to run into a situation where you want them
             | without even knowing what the concept of a GAT is.
             | 
             | Rust gets a lot of unfair criticism of "adding new stuff"
             | when a lot of what is "added" is actually removing
             | restrictions and making it where a developer has _less_ to
             | learn.
        
           | downvotetruth wrote:
           | Generics being a crippled dependent types lambda axis is
           | still infinitely more complex than chaining product &
           | coproduct (sum) data types.
        
             | kibwen wrote:
             | Please elaborate? Keep in mind that Rust isn't about making
             | the simplest or most expressive language possible. Rather,
             | it's about pushing the envelope on what sort of
             | expressiveness we can soundly get away with while still
             | benefiting from mechanical sympathy given the current
             | state-of-the-art of optimizing compilers (and, also, while
             | not being so foreign as to cause C-style language
             | programmers to run away screaming).
        
               | downvotetruth wrote:
               | A long form explanation would be best be found some where
               | else, maybe some day this will be an excuse to stop by
               | the Engineer's Club.
        
         | api wrote:
         | This isn't so much the introduction of a new concept or
         | abstraction as the removal of what feels like an artificial
         | limitation. You should be able to use a generic in a trait in a
         | type defined in that trait, and when you can't it feels broken.
        
         | epilys wrote:
         | Well you don't have to use it just because it is added, but it
         | will allow library writers to provide more ergonomic
         | interfaces. This specific type system feature allows for stuff
         | that weren't possible before but make sense and you'd expect to
         | be valid code that compiles:
         | 
         | the most common example is the lending iterator. Have a struct
         | that owns a vector of data. Can you implement an iterator that
         | can return a reference of each item when you call next()? Not
         | without GATs, because each time you return from next() you're
         | creating a new lifetime that doesn't exist in your trait
         | definition.
         | 
         | That's why current standard library iterators are basically
         | structs that own a reference to what you iterate. See the GAT
         | RFC which explains this concept much better than I can:
         | 
         | https://github.com/rust-lang/rfcs/blob/master/text/1598-gene...
         | 
         | TL;DR it's not a "new" feature per se but something that could
         | have been present from the beginning without making the
         | language different.
        
         | [deleted]
        
         | whatshisface wrote:
         | GATs 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]
        
           | petrosagg wrote:
           | The 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]
        
             | [deleted]
        
             | tialaramex wrote:
             | Note however broader Const Generics, allowing you to use
             | your enumerated Hat type as a constant parameter to a type,
             | producing PigInAHat<Hat::StrawBoater> as a distinct type
             | from PigInAHat<Hat::Top> are not yet in stable Rust and
             | aren't on the near horizon.
             | 
             | The idea is that any types which Rust can see for itself
             | can be trivially compared for equality will eventually
             | qualify for this purpose, so your Hat enumeration, or a
             | structure with four integers and a boolean in it, or
             | anything that Rust says "Yeah, I'll just memcmp that for
             | equality" would qualify. No floating point numbers, no
             | strings, nothing actually crazy. But this is in some
             | undefined future, for now we just have min_const_generics
             | which is basically the fundamental integral types as
             | constants in generics.
        
       | Sytten wrote:
       | One step closer to native async trait support! This is really a
       | good day for rust.
        
       ___________________________________________________________________
       (page generated 2022-09-13 23:01 UTC)