13 ms·
Rust 1.65.0
- deleted 4y ago[deleted]
- nicoburns 4y agoContext for those who don't follow Rust development closely: This release stabilises Generic Associated Types (GATs), a limited form of Higher Kinded Types. This is only an MVP release, but it already includes enough to be useful, and has been a huge multi-year effort (the RFC for the feature dates to April 2016). Novice users of Rust probably won't use this feature directly, but it gives a lot more power to library authors to write more flexible APIs while still keeping all of Rust's strict correctness guardrails (i.e. exposing a safe API). It will also form the basis of the upcoming "async functions in traits" feature. This is probably the most significant Rust release in the last couple of years.
- zozbot234 4y agoThe stabilization of GAT's was previously discussed https://news.ycombinator.com/item?id=32829806 https://news.ycombinator.com/item?id=32829806 From that thread, a link https://www.fpcomplete.com/blog/monads-gats-nightly-rust/ https://www.fpcomplete.com/blog/monads-gats-nightly-rust/ to a comparison of GAT's w/ HKTs as seen in high-level functional languages. Note that the version of GAT's provided here is a MVP and might be unable to express some of these patterns.
- 4m1rk 4y agoThis topic made me think that you'll eventually have to support all FP principles in a strongly type safe language like Rust which reminds me of Scala FP community. I'm not sure if it ended up being a good thing for Scala long-term. I also wonder whether Linux kernel community would adapt these concepts or reject them for the sake of KISS.
- queuebert 4y agoBest thing since const generics.
- afranchuk 4y agoI agree with the significance. I've liked the additions over the past few years of course, but the last time I felt a release was this significant was async, I believe 1.39, about 3 years ago. And coincidentally, the times I've wanted to reach for GATs have been when dealing with Futures (specifically dealing with lifetimes of Futures produced by Fns; basically what gates async functions in traits). I'm excited to be able to finally use them in my APIs!
- echelon 4y agoNo kidding, this is big! Data structures are going to get easier. > It will also form the basis of the upcoming "async functions in traits" feature. I can stop using https://crates.io/crates/async-trait https://crates.io/crates/async-trait !
- kibwen 4y agoNot just yet, the two big blockers on async methods are: 1. The ability to use generics in associated types 2. The ability to use `impl Trait` in associated types GATs provide the first, but the latter is still being worked on. The good news is that the implementation has matured greatly this year and appears to be in a state where stabilization could be considered. AFAICT this work is being done in the broader context of async methods, tracked here: https://github.com/rust-lang/rust/issues/91611 https://github.com/rust-lang/rust/issues/91611
- mellosouls 4y agoBefore going into the details of the new Rust release, we'd like to draw attention to... [political cause] The cause in this case is undeniably worthy, its an awful situation in an often crappy world, but what does it have to do with this release? Where do you start and stop with the issue-raising in technical release news?
- Vecr 4y agoIranian women must be armed with the best weaponry available. Support Iranian women by programing the next generation suicide drone in Rust today!
- netule 4y agoYou can skip over the paragraph and get to the meat of it. If you don't like it, don't read it.
- rat9988 4y agoHopefully you'll do the same with comments you don't like.
- jimcavel888 4y ago
- cshimmin 4y agoThe answer to your question is right there in the sentence. They would like to draw attention to it.
- FartyMcFarter 4y ago> Where do you start and stop with the issue-raising in technical release news? You start and stop exactly where you want to - no one owes you or anyone else technical release news without this kind of statement.
- 4y ago
- Fiahil 4y agoThis is it ? This is the GAT release ? Should we celebrate now or wait a bit more ?
- scottlamb 4y agoI'm not fully celebrating GATs yet due to all the limitations mentioned in the linked stabilization blog post. [1] I'll be ecstatic if and when I can write a std::iter::Iterator impl that borrows from itself. Fingers crossed that can happen. And I'll be watching to see what libraries implement based on this MVP. I'm celebrating other things in this release. let else will be great for ergonomics. Stable backtraces in std, split debuginfo on Linux, and const offset_from all address pain points for me. (Backtraces will be more useful though when the provider API lands. Then I think we'll be able to have really great error chains. Right now, there's no obvious way to go from a &dyn std::error::Error to a backtrace without guessing the concrete error type and downcasting, and the same problem applies to other forms of context I'd love to have.) [1] https://blog.rust-lang.org/2022/10/28/gats-stabilization.html https://blog.rust-lang.org/2022/10/28/gats-stabilization.htm...
- FullyFunctional 4y agoThe break from label is something I have needed and while I could make a workaround with loops, clippy didn’t like that at all, sigh.
- mbStavola 4y agoThis release is absolutely amazing! It has a bunch of neat stuff that quite a few people have been waiting on for a while now: - Generic Associated Types - Let-else - Labelled break - Stable Backtrace API - Split debug info on Linux Huge thanks to all the contributors and maintainers!
- xavxav 4y agoWhile GATs are undeniably cool, I think I'm actually most excited by the enabling of MIR inlining. Rust level optimizations have a real potential to increase performance and decrease compilation times, and inlining is one of the most important primitives for that.
- weinzierl 4y agoRust level optimizations sound promising. I could not find a good high level explanation what inlining means in this context and how it facilitates Rust level optimizations. I've read https://rustc-dev-guide.rust-lang.org/mir/index.html https://rustc-dev-guide.rust-lang.org/mir/index.html and https://blog.rust-lang.org/2016/04/19/MIR.html https://blog.rust-lang.org/2016/04/19/MIR.html but both did not enlighten me regarding inlining. Could you ELI5 or point me to relevant documentation?
- nicoburns 4y agoI think inlining is function inlining, which is an optimisation that lots of compilers do. The change here is to move (some of) that earlier in the compilation process (in the "middle end" of the Rust compiler rather than in the LLVM backend), which can make things more efficient by reducing the total amount of work that needs to be done.
- weinzierl 4y agoThat makes sense, thanks!
- xavxav 4y agoFor inlining in general, I think the wikipedia article is good https://en.wikipedia.org/wiki/Inline_expansion https://en.wikipedia.org/wiki/Inline_expansion. The reason it's so important is that inlining synergises with other optimizations, its often run before or after other passes like constant propagation. Consider something like: fn add(x : usize, y : usize) -> usize { x + y } fn main() { add(5, 1) } Without inlining we can't easily optimize the code of `main`. However, if we inline `add` into main, constant propagation will then directly see `5 + 1` and optimize that into `6`.
- epage 4y agoFor me, the exciting parts are in > Libs: Don't generate PartialEq::ne in derive(PartialEq) Meaning: Smaller generated code leading to faster compile times > Cargo: Take priority into account within the pending queue. When not enough CPUs are available (particularly CI), cargo will now prioritize crates with the longest dependency chain. We are wanting to be even smarter about which crates get priority but we still need to figure out what are acceptable heuristics (as we don't want to hard code crate names)
- kibwen 4y agoThanks to you and the Cargo team for all your efforts!
- epage 4y agoThanks though lqd is the one to thank the most for the performance work. I really appreciate the build time performance folks (nick, lqd) are looking at things holistically rather than staying in one specific domain.
- brundolf 4y ago> Don't generate PartialEq::ne in derive(PartialEq) I had to look at the docs to understand what was going on here so I thought I'd share: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html https://doc.rust-lang.org/std/cmp/trait.PartialEq.html Apparently the PartialEq trait has two methods - eq and ne (equal and not-equal, == and != respectively). Normally you only implement eq, because ne has a default implementation that's just !self.eq(other). The docs even say: > Implementations must ensure that eq and ne are consistent with each other > The default implementation of ne provides this consistency and is almost always sufficient. It should not be overridden without very good reason. So I'm guessing that `derive(PartialEq)` used to actually generate a fresh ne in each usage (even though presumably it was equivalent to !self.eq(other)), instead of just falling back to the default implementation. I can definitely see that having an impact on compile times. Do I have that right? Addendum: Now I'm trying to think of a case where you'd want a custom implementation of ne... I'm not sure I can come up with one
- mastax 4y ago`let else` looks strange to my eyes on first glance, but I can remember many cases when it would have been nice to have. (Not to mention, all Rust syntax used to look strange to my eyes so that's not a very useful criterion). Break from labeled blocks is a pretty niche thing. I can remember a few cases it would have been useful, but I'm not sure I'll remember the feature exists next time it comes up. I'm glad that GATs are finally here. I tend to be wary of complex type-system things. I can remember being a new rust programmer around 1.0, dealing with some library with a perhaps-overly-clever API with complex traits and lifetimes and being very frustrated randomly changing code trying to get it to compile. It didn't help that rustc error messages and rustdoc weren't as good and we didn't have any sort of language server back then. Perhaps I'm just not very smart. But even with my focus on simply-typed APIs I've run into several cases where I couldn't do something the obvious way because it needed GATs. I used to be a lot more involved with Rust, reading a lot of /r/rust and blog posts and issue trackers. I get a warm wistful feeling seeing things like GATs, rust-analyzer, and MIR inlining get stabilized after all these years.
- zozbot234 4y ago> `let else` looks strange to my eyes on first glance AIUI, this is a rather specialized feature that only supports diverging code in the "else" block. I assume that the weird syntax was purposely chosen to suggest something like that.
- queuebert 4y agoHow does this improve on binding the `Err`? Edit: I see now in the first example: let (Some(count_str), Some(item)) = (it.next(), it.next()) else { panic!("Can't segment count item pair: '{s}'"); }; Binding the error here would be much verbose, since both must succeed. Edit2: Doh, obviously `None` in this example, not `Err`.
- kibwen 4y agoI don't find the syntax weird, I think it's perfectly cromulent with the existing capabilities. To wit, pattern matching in `let` has always been possible: let (x, y) = (1, 2); ...But only for patterns that can never fail. For enums, not all patterns are irrefutable: let Some(x) = Some(42); // error, Rust can't tell that RHS isn't `None` Note that some languages with pattern matching do allow the above, e.g. OCaml does, and just panics if the match doesn't succeed (so equivalent to `let x = Some(42).unwrap()` in Rust). But Rust favors exhaustive pattern matching, so that wasn't a good fit. The way that Rust solves this is via `if`-style constructs. So you already have `if let`: if let Some(x) = Some(42) { // `x` exists in here } This produces an inner scope where the contents of the enum are bound. And you can use `else` here as well: if let Some(x) = Some(42) { // `x` exists in here } else { // branch where `x` doesn't exist } So the `let else` syntax feels like a natural continuation to me: let Some(x) = Some(42) else { // branch where `x` doesn't exist } // `x` exists here This reduces the nesting required in several common cases of using enums, which makes code easier to read. (Of course, the interesting thing is that since `x` exists in the outer scope, the compiler requires the inner scope to never reach the outer scope (it must "diverge", by returning or panicking or infinite looping or whatever), which is an extra restriction above what a normal `if else` requires.)
- idsout 4y agoAnyone know of some interesting crates that can now be used on stable thanks to this release?
- kibwen 4y agoHere's a comment from the GAT stabilization PR that compiles a list of crates that use GATs or would like to use them: https://github.com/rust-lang/rust/pull/96709#issuecomment-1173170243 https://github.com/rust-lang/rust/pull/96709#issuecomment-11... Here's a collection of comments from the same PR from users arguing for stabilization: "I work on chumsky, a parser combinator crate. I've recently been experimenting with GATs internally as a way to control exactly what code Rust generates. Instead of praying to the LLVM gods that the compiler might optimise things, I use a GAT to project a particular parsing 'strategy' into the implementation of parsers. I've found that I can significantly improve the performance of the library by an order of magnitude, even beating out hand-written parsers, nom, and serde_json (with several caveats) without harming the library's expressivity (and, in fact, improving it). This all happens without the GATs themselves being exposed to library users at all." https://github.com/rust-lang/rust/pull/96709#issuecomment-1118355537 https://github.com/rust-lang/rust/pull/96709#issuecomment-11... "The first time I realized the Iterator trait was insufficient for what I wanted was before Rust 1.0 in 2014 when I wrote one of the first versions of the csv crate. All I wanted to do was write an iterator that lent out a borrow of an internal buffer in order to avoid allocating a new record on each iteration." https://github.com/rust-lang/rust/pull/96709#issuecomment-1118627760 https://github.com/rust-lang/rust/pull/96709#issuecomment-11... "I've been using GATs on nightly for a little less than a year for various experimental proc-macro crates. I can only say that GATs simplify a lot of things for me! I'm not doing things like LendingIterator, my interest is more in "DSL"s. Things like e.g. generate a struct that temporarily stores all the parameters to some function (where some of those parameters will be non-static references). The main concern will often be how much code can I avoid autogenerating i.e. is it possible to write abstractions as libraries over these things. GATs allow me to do that with ease. [...] The one I'm currently working on is unimock. The GAT stuff is only in the gat-mock branch, not released on crates.io yet. That GATified trait is MockFn." https://github.com/rust-lang/rust/pull/96709#issuecomment-1119760258 https://github.com/rust-lang/rust/pull/96709#issuecomment-11... "There is no way to use async traits in an embedded context (no_std) without GAT's or pulling in the alloc crate (to use async-trait). Pulling in alloc for most embedded platforms is not feasible, therefore we are currently locked to nightly for the embedded-hal-async crate." https://github.com/rust-lang/rust/pull/96709#issuecomment-1150438541 https://github.com/rust-lang/rust/pull/96709#issuecomment-11... "Issue #95 on the RustAudio crate for example says, "The first [solution] would be to make PortType generic over a 'a lifetime...however, this has a cascading effect, which would force all downstream users of port types to specify their lifetimes". Pythonesque made a simpler point here, "Without GATs, I ended up having to make an Hkt trait that had to be implemented for every type, define its projections, and then make everything heavily parametric and generic over the various conversions."" https://github.com/rust-lang/rust/pull/96709#issuecomment-1167220240 https://github.com/rust-lang/rust/pull/96709#issuecomment-11...
- kevincox 4y agoI know GAT is a "bigger feature" for the language but personally I'm most excited about `let else`. It is very common to write code such as: let foo = match do_something() { Ok(f) => f, Err(e) => { // Do some error handling, maybe log a warning, maybe skip this item and continue... } }; This small change makes that so much more clear, removes the silly first row and removes a level of indentation. let Ok(foo) = do_something() else { // Do some error handling, maybe log a warning, maybe skip this item and continue... };
- echelon 4y agoSo much of my code is this. I love this addition too. I'm very impressed with how much good stuff is in this release. The Rust team is killing it.
- adamch 4y agoExcept the let-else version has one big disadvantage. The 'match' version has bound the error to `e`, so you can log that error or inspect it. The 'let-else' version can't read the error, so its log message can't be as useful. You can't check if it's a specific error, or include the error in logged messages. It's still convenient, but in really limited circumstances, AFAICT. This week I'll be going through the various Rust projects I maintain at work, seeing if there's useful places for let-else.
- vasilakisfil 4y agoyou are right, not so useful for Result type, but still, it comes handy for Option types (since None doesn't hold anything).
- etra0 4y agoAgree, I don't know if it's that useful for `Result<T>`, but for `Option<T>`, there has been a couple of times I've written if foo.is_none() { return; } let foo = foo.unwrap() Now I can do simply let Some(foo_unwrapped) = foo else { return; } which is prettier than the `if let (...)` to just unwrap it IMO.
- GolDDranks 4y agoThe most significant Rust releases, IMO: 1.00: lang/stdlib stability 1.13: the ? operator 1.15: custom derive 1.31: non-lexical lifetimes, new module system, const fn 1.39: async/await 1.51: const generics mvp 1.64: GATs ← we are here! wahoo!
- tialaramex 4y agoIMO Arrays implementing IntoIterator was significant because it means there isn't a weird special case to teach newcomers about, and because it requires a hack to make it work (in older Editions the fact Arrays are IntoIterator is hidden during method resolution to prevent old code from breaking).
- kibwen 4y agoI'd say that "Arrays implementing IntoIterator" falls under the umbrella of "const generics", which is also missing from that list. :P
- GolDDranks 4y agoAh, I knew I was missing something! Added both 1.31 and 1.51
- nicoburns 4y ago(nit: todays release with GATs is 1.65 not 1.64)
- GolDDranks 4y agoThanks, can't fix that anymore but duly noted.
- wooque 4y agoUnrelated, how is the market for Rust devs? Anyone successfully transitioned from Node.js/TypeScript/Python background (aka higher level languages) to Rust?
- lijogdfljk 4y agoRe: transitioning to Rust: For context: I started out a passionate and evangelical Python "duck typing" proponent. Eventually migrated to Node, as it let me in the browser via JS (i'm fond of web tech). Eventually Go caught my eye due to types (before Typescript really existed) and so i stayed there for a while. Each of these lasted ~5 years. These days i'm a heavy and solely Rust user.. going on ~3 years now iirc. Both in my work life, and home life. The more experience i got in my career the more i loved types, so Rust's type system wasn't a shock to me. Yes, it was the most in depth typing i had used, but for me it was a natural transition. I was wanting types to solve problems for me. Rust felt very natural in that sense. I advocate that Rust can be easy to learn if you focus on your bite sizes. Learn Rust with a keen eye for what looks like big and small bytes, and never exceed your mouth size. In the beginning lifetimes are scary, so avoid them - clone or `Arc` like mad. Be wary of heavy generic usage. Rust has lots of rope to hand yourself with, should you go looking for a noose.
- mplanchard 4y agoI can’t really speak to the market right now, but I transitioned to Rust from Python and Typescript in April of 2021. I started learning Rust in I think 2018. I had a couple of decently sized Rust open source projects under my belt, one of which I had managed to get some time to work on at $previous_job, since we integrated it into our react client via WASM. The company I joined is working on HTTP network proxy stuff in relation to fraud prevention. I didn’t have any professional experience in low level languages. I had some hobby/school experience with C and C++, but nothing recent. Learning rust was not too bad. Took me a couple of tries to get going, but once I got the basics down, expanding from there was pretty straightforward. At the time I was looking for a job, a solid majority of Rust jobs were in cryptocurrency or adjacent companies. I wasn’t interested in that, but I still found plenty of places to apply to. I got responses from almost all of them, and was able to pick between my top choices. My understanding is that now there are many more non-crypto jobs than there were, although I don’t know to what extent that has been affected by recent economic conditions.
- deleted 4y ago[deleted]
- chrismorgan 4y ago> As the final step of the RLS deprecation, this release has replaced RLS with a small LSP server showing a deprecation warning, advising users to migrate to rust-analyzer. RLS is no longer deprecated, but removed. “Deprecation warning” means “FYI, you shouldn’t be using this, but it’ll still work for now”. This is an obsolescence notification, not a deprecation warning. I fear we’re losing the fight for the meaning of the word “deprecate”. Yet we have no other word or even phrase to convey what it has historically meant.
- pie_flavor 4y agoObsoleted means approximately the same thing as deprecated, except for verb subject.
- chrismorgan 4y agoThey’re often similar, but there are very important differences. (And I led with the word “removed” rather than “obsoleted” for a reason; perchance it was unwise to use the term obsolescence at all.) Obsolescence is ambiguous. In common usage it means a thing is not maintained and will generally become harder and harder to use due to the lack of maintenance and support, so that at some point it will probably stop working and be unfixable. But especially in the software field it has long also been used to indicate things that actively don’t work any more because they’ve been replaced by something else. In short, “obsolete” already serves as what people are ruining “deprecated” to mean: maybe it works, maybe it doesn’t, but sooner or later it won’t work. Deprecation, however, must not signify removal. It is purely a form of discouragement of something that still works, at least for now. See https://en.wikipedia.org/wiki/Deprecation https://en.wikipedia.org/wiki/Deprecation.
- aliqot 4y agoComing from the go side, let else is lookin kinda juicy
- philosopher1234 4y agolol... but why? trying to imagine where you would use this in go... just the pattern matching?
- aliqot 4y agoeven if rust is more of a weekly than a daily to me, it helps to know what other camps are doing so I know what I'm missing. this is interesting to me
- zbentley 4y ago> where you would use this in go Error checking; golang's error handling arguably reverses the happy/sad paths of code syntactically, and some users don't like reading things error-first.
- SaintSeiya84 4y agoRust is getting as bloated as C++, only bored developers that entertain themselves by more and more syntactic sugar or looking smart, instead of actually writing software, will be glad of this versionitis of programming languages.
- davidatbu 4y agoHave you heard of the No True Scotsman fallacy?
- mpcannabrava 4y agoDoesn't rust feel a bit too heavy weight? It feels like the language packs too much firepower, can there be downsides to that? C long life seems to be, in part, because of its simplicity.
- pkolaczk 4y agoMost of the new development is not about adding new features but about removing limitations and making existing features more orthogonal. GATs technically aren't introducing a new thing. They just allow to use the already existing generic syntax on more things. Similar thing with allowing impl Trait in more places and async traits.