Become a fan of Slashdot on Facebook

 



Forgot your password?
typodupeerror
×
Programming

New Features In Rust Include Generic Associated Types (GATs) After Six-Year Wait (rust-lang.org) 68

The newest stable version of Rust, 1.65.0 includes generic associated types (GATs) — the ability to declare lifetime, type, and const generics on associated types. "It's hard to put into few words just how useful these can be," writes the official Rust blog.

An earlier post pointed out that "There have been a good amount of changes that have had to have been made to the compiler to get GATs to work," noting that the request-for-comments for this feature was first opened in 2016.

And Rust's types team also created a blog post with more detail: Note that this is really just rounding out the places where you can put generics: for example, you can already have generics on freestanding type aliases and on functions in traits. Now you can just have generics on type aliases in traits (which we just call associated types)....

In general, GATs provide a foundational basis for a vast range of patterns and APIs. If you really want to get a feel for how many projects have been blocked on GATs being stable, go scroll through either the tracking issue: you will find numerous issues from other projects linking to those threads over the years saying something along the lines of "we want the API to look like X, but for that we need GATs" (or see this comment that has some of these put together already). If you're interested in how GATs enable a library to do zero-copy parsing, resulting in nearly a ten-fold performance increase, you might be interested in checking out a blog post on it by Niko Matsakis.

All in all, even if you won't need to use GATs directly, it's very possible that the libraries you use will use GATs either internally or publically for ergonomics, performance, or just because that's the only way the implementation works.... [A]ll the various people involved in getting this stabilization to happen deserve the utmost thanks. As said before, it's been 6.5 years coming and it couldn't have happened without everyone's support and dedication.

Rust 1.65.0 also contains let-else statements — a new kind of let statement "with a refutable pattern and a diverging else block that executes when that pattern doesn't match," according to the release announcement.

And it highlights another new feature: Plain block expressions can now be labeled as a break target, terminating that block early. This may sound a little like a goto statement, but it's not an arbitrary jump, only from within a block to its end. This was already possible with loop blocks, and you may have seen people write loops that always execute only once, just to get a labeled break.

Now there's a language feature specifically for that! Labeled break may also include an expression value, just as with loops, letting a multi-statement block have an early "return" value.

This discussion has been archived. No new comments can be posted.

New Features In Rust Include Generic Associated Types (GATs) After Six-Year Wait

Comments Filter:
  • Will this make it easier to fly the Scrap Helicopter?

  • "We're now a Big Dog because we are just as convoluted as JavaCsharpC++!"

  • Off track... (Score:5, Interesting)

    by RedMage ( 136286 ) on Saturday November 05, 2022 @05:39PM (#63027411) Homepage

    I think Rust is a little off-track and going down the C++ route now. It started as a simple smart language that would be safer than C and reduce the number of initial avoidable bugs. Now it's a super semi-functional-generics-driven-wizz-featureoftheday language and I think that it's less approachable and usable because of that. I'm sure many will disagree with me, but my personal experience as a C programmer (and later Java then Scala) is that Rust isn't today what it initially advertised and has grown too far beyond the original design.
    Yeah, I'll get roasted and toasted over that, but remember people its an opinion and its born from my actual experience in looking to use the language. Not looking to ignite a flame war and really not interested in participating in one if you do. And yes, I know what this feature does and how it's used, and that's not the point.
    Again my opinion but C was powerful in its simplicity and approach-ability. It fell down because you could put a hole through your head and feet really easily by simple mistakes like pointer malpractice. Rust was supposed to help with that and I feel it did - but its losing that simplicity factor. It shouldn't be competing with C++.

    • It went off track on that route from the beginning. Your average Rust program looks a lot like C++ but with shorter keywords and such. It's like, "we want to type on the keyboard a lot, like C++, but also shorten some words so our fingers don't tire out." Really, in my view, C++ jumped the shark way back in the first standard when it doubled down on generics and thus stopped being object oriented. It was handy for me since so few others in the company could understand the obfuscated error message that t

      • It's like, "we want to type on the keyboard a lot, like C++, but also shorten some words so our fingers don't tire out."

        What a terrible idea. I'd love an example of a project that was late due to typing speed.

      • by rlwinm ( 6158720 )
        This is exactly how I feel. I wrote quite a bit of C++ in the 90s but without templates. It was perfectly possible to use normal OO to accomplish a great deal. I had looked at C++ as saving me the hassle of setting up VTABLES myself. But then with templates it attempted to become a meta-programming language. Which I think is a good thing - but not the way C++ did it. Scheme is a pretty good language for thanks to macro and lambda. C++ could have maybe made a pleasing syntax to be more like Scheme in C. But
        • I don't know, it struck me that basic templates were a *huge* boon for libraries - containers, iterators, etc. Anything that might pass around (handles to) user data that it didn't actually recognize. I never really got into Java precisely because their absence made type-safe programming extremely sketchy, and dealing with containers a tedious headache - having to manually cast data to the correct data type every time you access it.

          My biggest objection to template programming was the hideous error message

      • Re:Off track... (Score:4, Informative)

        by piojo ( 995934 ) on Saturday November 05, 2022 @10:22PM (#63027939)

        It went off track on that route from the beginning. Your average Rust program looks a lot like C++ but with shorter keywords and such.

        I disagree completely. One of the game changers is rich pattern matching combined with control flow (so you don't go into a code path unless your variable is exactly what you think it is, and you can bind its fields differently in a different code path). This means no more forgetting to do a null check or check an array size, because those checks are part of the control flow. (The traditional way is also available, but there's usually no reason to prefer it over the safer way.)

        A more controversial potential game changer is ownership and lifetime semantics; an object can't be owned by multiple scopes, and it can't be mutably owned by anyone if it's shared by other scopes. There's no denying this makes coding harder, though today's update should improve that a bit. Of course it is possible to write traditional code (unsafe), but trying to jump through the right hoops to have your code considered safe wrt ownership/lifetimes is sometimes very difficult. In other cases, it's very easy and gives a quick win to prevent bugs.

      • ...don't try to be clever...

        Words to live by. My whole life I have railed against "the curse of the clever programmer". Just try to be clear and understandable - that is a trick most programmers never learn, but it is one of the only important ones.

    • Re:Off track... (Score:5, Informative)

      by Freedom Bug ( 86180 ) on Saturday November 05, 2022 @07:15PM (#63027637) Homepage

      GAT's increase the simplicity of Rust in 3 different ways:

      GAT's make Rust 1.65 a *simpler* language than 1.64 was. GAT's aren't new, Rust already had Generics and Associated Types, GAT just lets you use them together. Before the compiler would spit out an error saying "you can't do that" when you used them together, now it just works.

      There are several libraries which will have much simpler interfaces with this change.

      Also, GAT's are massively simpler and provide almost all of the complexity of Higher Kinded Types (HKT) like you find in Haskell et all.

      Increased simplicity, more power.

      • by ls671 ( 1122017 )

        Interesting, some day I might search to find out what GATs are :)

        I was expecting someone might enlighten us in the comments but I haven't found anything.

        Who knows? I might even already have used them without knowing since I did use generics for some stuff already.

        • by 93 Escort Wagon ( 326346 ) on Saturday November 05, 2022 @11:35PM (#63028053)

          Interesting, some day I might search to find out what GATs are :)

          Gats are often found in close proximity with molls.

        • Associated types are a way of specifiying types in an interface (a trait in Rust). There are most useful where one type in a trait varies independently of the implementing type. So, for an example, different instances of an iterator can return many different types of thing.

          Generics you probably already know -- instead of specifying a type as a concrete type, you specify it as a variable.

          GAT you just put the two together. It's more useful in Rust than it sounds because lifetimes are also specified as a type.

          • Yeah, not knowing Rust that's what it sounded like to me. And that's the best kind of feature to add to a language - the kind that makes the programmer-facing concepts more consistently orthogonal, regardless of what they look like under the hood.

            Languages, like libraries, are best when they hide any kludgy ugliness from the user to present a consistent, predictable interface.

          • by ls671 ( 1122017 )

            Associated types are a way of specifiying types in an interface (a trait in Rust). There are most useful where one type in a trait varies independently of the implementing type. So, for an example, different instances of an iterator can return many different types of thing.

            Thanks! It sounds like I have done this a few time in Java like here, if I understand correctly at least. If you use "? extends Object" you can basically return anything, what do you think? :)
            public interface Treeable extends AclManaged {
            Map<String, ? extends TreeableLocale> getLocales();
            Treeable getOwner();
            Treeable getParent();
            Collection<? extends Treeab

    • Comment removed based on user account deletion
    • Feature creep is one of the foundation traditions of geekdom.

      The way I describe it is that programmers are technological artists. There's a real thrill in being able to create something out of nothing, and you tend to see a lot of people in this industry with huge egos with a need to show off. It's even worse in the open-source community, where people are typically paid with emotional fulfillment, rather than money.

      The Rust community is full of people who insist that they are better, safer, and smarter th

    • by Jeremi ( 14640 )

      I think Rust is a little off-track and going down the C++ route now. It started as a simple smart language that would be safer than C and reduce the number of initial avoidable bugs. Now it's a super semi-functional-generics-driven-wizz-featureoftheday language and I think that it's less approachable and usable because of that.

      I expect you're right -- I tried to grok the linked blog post and failed miserably, despite having previously read Programming Rust [amazon.com] from cover to cover and understanding that fairly well.

      On the other hand, isn't that expected, even inevitable? Every language that actually gets used ends up getting expanded to meet the needs of its users, and gets more elaborate/complicated as a result. The alternative (never expanding the language's capabilities, in the name of keeping-it-simple) would cause people who ne

      • On the other hand, isn't that expected, even inevitable? Every language that actually gets used ends up getting expanded to meet the needs of its users, and gets more elaborate/complicated as a result.

        I'm not a heavy Python user, but hasn't Python avoided that fate? It seems like it... or at least I don't notice Python users complaining about that.

        • It is a constant tension, though, for language designers. Every new language feature (from the various comprehensions, structural matching, progressive typing) is met with push back saying "do we really need this".

          The idea that Rust is rushing headlong into new features is a difficult one; it's not that old a language, but this has still taken 6 years with lots of people arguing against on the grounds that it adds complexity. We will see where Rust ends up, but for a language of its age, it's pretty conserv

        • Python? So many lol.

          It now has optional typing which is ignored by the interpreter and only checked by external tools of which there are several and they don't necessarily agree on the results.

    • by ljw1004 ( 764174 )

      I think Rust is a little off-track and going down the C++ route now. It started as a simple smart language that would be safer than C and reduce the number of initial avoidable bugs. Now it's a super semi-functional-generics-driven-wizz-featureoftheday language and I think that it's less approachable and usable because of that.

      You reckon? My take on 1.65 is that Rust originally had features A1,A2,B1 and now they're just completing+simplifying the original vision by adding B2.

    • I think Rust is a little off-track and going down the C++ route now.

      That's how it always was. It was built by C++ programmers, to appeal to C++ programmers. Elegance isn't part of the equation.

      Of course, C++ programmers will say, "It may not be elegant, but at least it has features!" And that is the entire crux of the argument. History has sadly shown that elegance loses every time.

    • by gweihir ( 88907 )

      Feature creep is a sign of amateurs at work. Or some corporate assholes that want to take over the world. Competent engineers respect KISS above anything else.

    • I tend to agree. Adding more and more features to languages is rarely a good idea.

      In this particular case: "break" is something used by lazy/poor programmers, when they can't be arsed to structure their code cleanly. Whatever TFA says, a break *is* a "goto" and is the first step to spaghetti code.

      • No one has anything better, regardless of the specific syntax.

        Initializing a specific piece of hardware requires going through all of the steps, in the correct order. If one of those steps fails, it is mandatory to clean up after yourself. The cleanest way to do that is to have all of the possible failures go to one bit of code that unwinds the initialization, step by step. Deciding which initialization steps need to be unwound can be accomplished by leaving breadcrumbs as steps succeed, or by putting mu

      • exceptions are a limited form of "goto" and a loop break is a limited form of "goto" as well. I have no problem with scope breaks; especially for nested loops. Not being able to exit more than 1 loop requires additional logic to achieve the same result and this adds unnecessary cognitive load. The problems happen when you cross function boundaries and this is where exceptions can create "goto" like problems where program flow jumps quite far from the source of the branch condition.

        Every language seems to

  • Trying to design a language so that programmers who are ignorant of the requirements of parallel programming can do parallel programming is a recipe for disaster.

    Making ignorance OK is always a bad idea.

    • by Jeremi ( 14640 )

      Trying to design a language so that programmers who are ignorant of the requirements of parallel programming can do parallel programming is a recipe for disaster.

      It's still better than the status quo, where ignorant programmers do parallel-programming in a language that was not designed for them.

    • by ljw1004 ( 764174 ) on Saturday November 05, 2022 @09:31PM (#63027851)

      Trying to design a language so that programmers who are ignorant of the requirements of parallel programming can do parallel programming is a recipe for disaster.

      I'm someone who knows a fair bit about parallel programming. (I created the "async/await" feature in C#, that's now been copied into many other languages). I *really* enjoy programming Rust. Even someone who's an expert at parallel programming still benefits from Rust.

      • by piojo ( 995934 )

        Wow, what a privilege it must have been to work on something so fundamental and critical! I really enjoy the simplicity of async/await in C#. It is pretty much seamless to use. I also enjoy the ability to make any class into an awaiter (or stick it in a TaskCompletionSource).

        I also really enjoy Rust, so maybe there is some mental compatibility at play here. (Though I struggle with lifetimes more than a really skilled Rust developer would.)

      • Re: (Score:2, Insightful)

        by _merlin ( 160982 )

        OK, I haven't actually used async/await in C++, but I've read Raymond Chen's blog posts about it, and they've left me utterly confused about what it's supposed to do and how it works. Now I've also read his blog posts about C++ features that I do use, and my immediate thought is, "I'd sack someone if they wrote code like that." Is this another case of Raymond Chen being stupid, or is the feature actually confusing?

      • I had to look up that feature as I don't do c#.

        I worked on something similar back in 2006 for the PS3, except it was more generalized synchronization primitive. We called it a Gate, when created you set a "toll amount" and other tasks could pay a "toll" after completing sub-tasks, when the total "toll" was paid the Gate opened and the waiting task could proceed.

        • by ljw1004 ( 764174 )

          The nature of async/await isn't specifically about concurrency, although that's its primary use-case.

          Instead it makes sense to think of async/await interms of `callcc` that used to exist in other languages like ML, whose job was to pack up the remainder of the function in a closure/lambda that can be executed later. It's a special case where the remainder of the method will be executed at most once, exactly like Rust's FnOnce.

          The problem with callcc, and indeed with all async code that's done with callbacks

    • by gweihir ( 88907 )

      Trying to design a language so that programmers who are ignorant of the requirements of parallel programming can do parallel programming is a recipe for disaster.

      Making ignorance OK is always a bad idea.

      I completely agree. Cretins will always find things to break and to make insecure. Telling cretins they are "coders" or even system programmers is a really bad idea. It is like we allow everybody to do electrical wiring. The houses burning down are nicely observable in the software field. Writing software is not something amateurs can do competently. The Rust idiots are making things worse not better.

      • The cretins will create the software you rely on for your well-being whether you like it or not, you can mitigate their damage or make it worse. Those are the only options.

        • You're not mitigating danger, you're making the issues more subtle.

          Also, by relying on the underlying language to handle concurrency you're throwing away efficiency. I'd bet a Rust program will be far less efficient than one written in another language by someone who knows what they're doing, but I suppose getting some "free" concurrency from Rust is better than nothing for those ignorant, although it will hurt overall system efficiency.

    • There is a certain breed of C programmer who is utterly in love with their own intellect. They are the towering masters who make no mistake and produce prefect bug free code.

      But what I don't understand: we have these amazing programmable machines which we love to program , so why are some people so against the idea of programming the machines to automate away tasks.

      It is possible to do well written C code but it is very hard and lower productivity. Compare the features and performance of open BSD to Linux,

      • Oh, I'm ignorant of a whole lot of things, but what I'm not ignorant of is how the hardware functions all the way down to the transistor level.

        Because of the knowledge base I've accumulated over 35+ years of doing the nasty bits for a living makes we wonder how most programmers even function when they have no clue to what the fuck is actually going on in the CPU. This is why I scoff at "magic" programming languages that are supposed to deliver us from having to actually know things. Without knowledge and

        • Yeah yeah, I get it, you think you're awesome and everyone else is a weak programmer. Meanwhile in the real world, well, there are those CVEs over there...

          • Oh, I know I'm awesome, at certain things.

            You need someone to write you a video driver or optimize some code for ridiculous performance/memory constraints? I'm your guy.

            Need someone to do some virtualized cloud bullshit that's best handled locally by a small microprocessor? Nope, I don't know squat about it. Find someone else. Not only am I completely ignorant of it, I have zero interest in it.

  • As alluded to before, this stabilization is not without its bugs and limitations. This is not atypical compared to prior large language features. We plan to fix these bugs and remove these limitations as part of ongoing efforts driven by the newly-formed types team.

    This doesn't inspire confidence.

    • Remember kids, you can fix all your memory overflows and still have massive security holes.

      • by gweihir ( 88907 )

        In fact, finding and fixing buffer overflows is pretty basic and pretty easy to do. If you have a clue. If you have no clue, no amount of language pixie dust will make your code secure.

    • by gweihir ( 88907 )

      It does not. Not in the least.

    • It depends on the type of the bugs. In this case, the known bugs mean that some things that you would expect to compile do not. And some things are rather more wordy and require additional type annotation than you would hope for.

      So, the known bugs are safe; they just prevent GATs from being feature complete. Of course, there may be unknown bugs, which make GATs unsafe. But, they don't know about them yet.

  • These changes will be really helpful. One critical feature is that more types of iterator are now possible. It's also nice that let binding can be used to fail if the binding fails ("if (we can't bind to this type/value) { return error }").

    I am a little surprised they added the binding failure check without allowing "if let" to be chained with other conditions, for example to combine the binding to some optional data and use that optional data in a check:

    if let (Some(max_len) = max_len) && data.len(

    • by piojo ( 995934 )

      To add to my previous note, if-let changing may not be a priority since there is a pretty friendly macro that accomplishes the same thing:


      if matches!(max_len, Some(max_len) if max_len == data.len()) {
          return data;
      }

      And the match construct is also pretty powerful, but it can get a bit verbose.

      • by flux ( 5274 )

        ..except max_len is not available in the block?

        And the alternative:

        match max_len {
                Some(max_len) if max_len == data.len() => { }
                _ => ()
        }

        is a bit more complicated.

        Personally though I would like to keep the language small enough not to need these little helpers when the same can be expressed with about the same number of symbols anyway.

        • by piojo ( 995934 )

          Good point about the binding.

          If-let chaining makes the language smaller, not bigger. Remembering that some scenario doesn't work is additional cognitive load, while if-let chaining allows one to think of "if let" as no different than "if". C# has shown that it's perfectly reasonable to treat variable binding/pattern matching as a boolean. matches! is a boolean. But of course, this feature needs implementation, and in that sense it would be a bigger language.

  • RIght now Rust is the go-to alternative to C. This new announcement has the distinct smell of feature-creep (I could be wrong, I'm not a systems developer) an makes me weary of Rusts long-term strategy. ... They have a good reputation as a potential successor to C, they should be very careful not to screw around with it.

    Rather build an IDE or some extensions to Rust and perhaps some Rust libs if they want to forage into application territory. ... Which they shouldn't, we've got enough PLs in that space alre

    • That was discussed extensively before they added GATs. But, GATs do allow you to define kinds of interfaces that many people want (and that is obvious even in the standard library where, for example, there is no interface for "thing that can produce an iterator"). And, they also discarded many other possibilites that would have achieve the same thing but at higher complexity (higher kinded types being an example which are widely used in languages that only type theorists are capable of using).

      it's not somet

"I'm a mean green mother from outer space" -- Audrey II, The Little Shop of Horrors

Working...