[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)