11 ms·
Rewriting Rust
- tskulbru 2y agoArticle aside, that page background messed with eyes while reading
- lagniappe 2y agoThat is a user responsibility.
- TheChaplain 2y agoTry Reader View in Firefox, has helped me with this article and many others.
- selcuka 2y agoI use a bookmarklet I found ages ago which is less invasive as it doesn't change the layout: javascript:(function(){var newSS, styles='* { background: white ! important; color: black !important } :link, :link * { color: #0000EE%20!important%20}%20:visited,%20:visited%20*%20{%20color:%20#551A8B%20!important%20}';%20if(document.createStyleSheet)%20{%20document.createStyleSheet("javascript:'"+styles+"'");%20}%20else%20{%20newSS=document.createElement('link');%20newSS.rel='stylesheet';%20newSS.href='data:text/css,'+escape(styles);%20document.getElementsByTagName("head")[0].appendChild(newSS);%20}%20})();
- josephg 2y agoAuthor here. Thanks for the feedback.
- bilekas 2y agoSeems rust has come full circle. Rewriting everything in rust.. Why not Rust! /s
- dloranc 2y agoBut Rust is written in Rust :)
- weinzierl 2y agoIt's a good collection of the usual suspects, when it comes to suggested improvements for Rust. The one point that stuck out for me is the comptime section. It approaches the topic from a security and supply-chain attacks angle, which is a way I never thought about it.
- feelingsonice 2y ago>And I don't know if it will ever be there. Progress on the language has slowed so much. When I first started using it, every release seemed to add new, great features in stable rust. Now? Crickets. Is frustration with Rust on the rise? I just started using Rust few month ago and absolutely love it. I can't tell what's going on with the Rust foundation so I can only judge by reading sentiments. Nothing would kill my vibe harder than knowing smart people thinks the language isn't doing great :(
- lionkor 2y agoJust look at the proposal to add an --only-dependencies flag to cargo-build. https://github.com/rust-lang/cargo/issues/2644 https://github.com/rust-lang/cargo/issues/2644 Its a clusterfuck of people misdirecting the discussion, the maintainers completely missing the point, and in the end its still not even been allowed to start. Cargo can download-only, it cant build only dependencies. If you, for whatever reason (ignoring the misleading docker examples) want to build your dependencies separately from your main project build, you are sol unless you want to use a third party dependency to do so.
- panick21_ 2y agoNo language can continue to add freatures at speed, specially not a low level one. Rust development is going fine, crickets is just inaccurate. It just takes a while to add new stuff with zero overhead and backwards compadible.
- antonvs 2y ago> Rust development is going fine, crickets is just inaccurate. Yeah. This is someone who's frustrated that he doesn't wake up to headlines that read "Hey babe, new Rust feature just dropped". If that's what he's looking for, he should probably switch to the Javascript ecosystem.
- culebron21 2y agoI think every tech eventually is taken to its limits, no matter that it enabled you things that were earlier impossible. With Rust, I made projects I wouldn't dare to in Python or weren't ever able to in C. You may think what people can do with MS Excel that was impossible with a desktop/pocket calculator, but also look at how huge Excel books can get that it starts crashing. I'd say Rust delivers well on most promises, but as your projects grow, you start getting unexpected costs, like every dependency bringing a dozen of others, and compile times getting longer and longer.
- culebron21 2y agoI think adding per-crate permissions to do undoable/unsafe things will lead us to permissions hell of devops in big deployments. Like Amazon S3 with gazillion options. I think it's time to do something radically different with 3rd party deps. Even if we put aside safety issues, each crate brings ~10 more dependencies by default (i.e. without any features turned on), which bloats compile times. Maybe it's better to be able to shard 3rd party crates, and not update them automatically at all?
- hnlmorg 2y agoThat’s a solution people already use (vendering and / lock files) but it doesn’t solve this particular problem. The closest to a solution we have is dependency scanning against known CVEs. Having per-crate permissions is, I think, the only way languages can evolve past this hell hole we call supply chain attacks. It’s not a silver bullet, there will be edge cases that can be bypassed and new problems it creates. But if it reduces the scope of where supply chains can attack and what they can do, then that’s still a massive win.
- josephg 2y agoAuthor here. Yeah thats my thinking. I also think you probably only need to restrict your dependencies. If you have a dep tree like this: a |-b |-c Then if crate a decides b isn't trusted, c would inherit the same trust rules. This would allow crates to be refactored, but keep the list of rules needed in big projects to a minimum. You just have to add explicit rules for sub-crates which need more permissions. Thats probably not a big deal in most cases. (You might still, sometimes, want to be able to configure your project to allow privileged operations in c but not b. But thats an edge case. We'd just need to think through & add various options to Cargo.toml.)
- culebron21 2y agoWhat if dep tree is like this: a |-b | |-c | |-c |-d |-c I may have read not carefully, but what happens if you allow crate X to write files, and it gets compromised? Should we set restrictions on per-call base instead? I see we may catch those situations when a crate starts reading/writing when it hadn't, or in an unexpected place, if we set restrictions per call, but this only limits the attack surface, not eliminates it. ...It may actually make 3rd party libraries such a big bureaucratic pain, that users will minimize their usage.
- knighthack 2y agoSince Rustaceans are so neurotic about rewriting everything in Rust, I genuinely thought that an article about rewriting Rust (in Rust) had to be a meta-satirical joke.
- nineteen999 2y agoThey want you (us?) to rewrite everything in Rust. Not them.
- simonask 2y agoWho is "they"? Seriously, who?
- nineteen999 2y agoThe parent comment referred to "Rustaceans". Check the first two words.
- SenorKimchi 2y agoThe Rust Evangelism Strike Force
- Ygg2 2y agoAre They in the room with us?
- Joeboy 2y agoWell, if you work on security-critical software that's currently written in a memory-unsafe language, I would say that's a good candidate for a Rust rewrite. Likewise if you work on a widely used library that's awkwardly slow because it's written in python. Which is not exactly the same as wanting everybody to rewrite everything in Rust, but I suppose it's the sort of thing that annoys nineteen999. There are also a lot of devs rewriting things in Rust for their own entertainment or whatever, which I think is the main source of the "rewrite everything in Rust" meme.
- dist1ll 2y agoI think the dependency situation is pretty rough, and very few folks want to admit it. An example I recently stumbled upon: the cargo-watch[0] crate. At its core its a pretty simple app. I watches for file changes, and re-runs the compiler. The implementation is less than 1000 lines of code. But what happens if I vendor the dependencies? It turns out, the deps add up to almost 4 million lines of Rust code, spread across 8000+ files. For a simple file-watcher. [0] https://crates.io/crates/cargo-watch https://crates.io/crates/cargo-watch
- M4Luc 2y agoAnother example is Axum. Using Go, C#, Deno or Node you don't even need any third party provided more or less secure and maintained lib. It all comes from the core teams.
- conradludgate 2y agoI bet most of those lines are from the generated windows api crates. They are notoriously monstrous
- dist1ll 2y agoYou're right, the windows crate alone contributes 2.2M. I wonder if there's a way to deal with this issue.
- lifthrasiir 2y agoThe exact size of the `windows` crate depends on feature flags, because parsing 2.2M lines of code is always going to be very expensive even when you immediately discard them.
- JoshTriplett 2y agoThe parser is shockingly fast. The slow parts come after parsing, where we process all those function definitions and structure definitions, only to end up throwing 98% of them away. A challenging architectural problem that several of us are trying to get someone nerdsniped into: inverting the dependency tree, such that you first check what symbols exist in a large crate like windows, then go to all the crates depending on it and see what they actually consume, then go back and only compile the bits needed for those symbols. That'd be a massive improvement to compilation time, but it's a complicated change. You'd have to either do a two-pass compilation (first to get the symbol list, then again to compile the needed symbols) or leave that instance of the compiler running and feed the list of needed symbols back into it.
- maverwa 2y agoI think there are fair complaints and good ideas in this. But I also think thats a bit hypocritical: They complain that there is a gigantic backlog of features in progress (as in "not in stable yet"), and then goes on to propose a lot of additional, quite fundamental and far reaching featues they'd like to see. Don't get me wrong: I'd like coroutines and a lot of other unstable/hidden features done as well. Function traits sound great, and I'd also like the whole Pin stuff to be easier (or gone?). But please, "Lets just extend the borrow checker and fix that" sounds very demeaning. Like no one even tried? I am by far no expert, but I am very sure that its not something you "just" go do. I like most of the proposed features and improvements, I mostly share the critique on the language, but I do not thing the "why not just fix it?" attitude is helpful or warranted. Theres tons of work, and only so much people & time.
- Arch485 2y ago> I am by far no expert, but I am very sure that its not something you "just" go do. As someone who has dabbled in compiler writing (i.e. I may be totally wrong), I believe that from a technical standpoint, modifying the borrow checker as proposed in the article (w.r.t. self-referential structs) is actually something you can "just do". The issues that come up are due to backwards compatibility and such, meaning it cannot be done in Rust without a new Rust edition (or by forking the compiler like in the article).
- mathw 2y agoBefore you can "just do" a change to the borrow checker you have to be able to precisely describe how those new behaviours for the borrow checker actually work, how it interacts with the rest of the borrow checker's behaviour and how it doesn't lead to unsoundness problems. Otherwise, you might as well just not have a borrow checker.
- Arch485 2y agoIndeed. In the case of self-referential borrows, this is not allowed because Rust wants copying structures byte-for-byte (e.g. `memcpy`) to always be safe. The solution was `Pin<T>` et. al., which gives a way to make some value immovable in memory. An equivalent yet simpler version of this system could be integrated into the borrow checker (this was a proposed solution for Rust), but as I said before, it would not be backwards-compatible, hence the need for `Pin`.
- rtpg 2y agoThe function trait section reminded me about effect systems and Purescripts row polymorphism[0], which is a great little way to be able to encode properties of your functions. I think Rust might quickly run into the “negative trait” problem trying to get that working, while embracing an effect system like Purescripts might get you the goods in a “principled” way. Though I haven’t thought about this deeply. [0]: https://rtpg.co/2016/07/20/supercharged-types.html https://rtpg.co/2016/07/20/supercharged-types.html
- conradludgate 2y agoI muuuch prefer pin to any move trait. Pin is a place property, not a type property. I think this post covers it nicely. https://without.boats/blog/pinned-places/ https://without.boats/blog/pinned-places/. It definitely should be more ergonomic though
- simonask 2y agoI don't know. In spite of Boats' great points, I think the programmer intuition definitely aligns more with it being a type property, in the sense that it enables the most interesting use case: self-referential values. All of that interacts badly with move semantics, and especially the lack of "guaranteed copy elision", but nevertheless...
- josephg 2y agoAuthor here. The first draft of this post spent a lot more time talking about Move. But I think the real question is: What syntax would let us author self-referential types. And, in a way that doesn't require Box-ing everything. (Rust's mantra is abstraction without overhead.) But then I thought about it more. Whatever you call it - Pin or Move - the point is to say "this struct contains a borrowed field". But we never needed Pin for local variables in functions - even when they're borrowed - because the borrow checker understands whats going on. The "Pin" is implicit. Pin also doesn't describe all the other semantics of a borrowed value correctly - like how borrowed values are immutable. I suspect if the borrow checker understood the semantics of borrowed struct fields (just like it does with local variables), then we might not need Pin or Move at all.
- smolder 2y agoI hate to say it since I'm generally against this kind of obstructive elitism, but I think that maybe one of the good things about rust is it's user-unfriendliness to amateurs. It has massive utility and ergonomy inherent to its design, but gatekeeping to keep away "left-pad" library authors and users is good for utility, too.
- JoshTriplett 2y ago> Now, there are issue threads like this, in which 25 smart, well meaning people spent 2 years and over 200 comments trying to figure out how to improve Mutex. And as far as I can tell, in the end they more or less gave up. The author of the linked comment did extensive analysis on the synchronization primitives in various languages, then rewrote Rust's synchronization primitives like Mutex and RwLock on every major OS to use the underlying operating system primitives directly (like futex on Linux), making them faster and smaller and all-around better, and in the process, literally wrote a book on parallel programming in Rust (which is useful for non-Rust parallel programming as well): https://www.oreilly.com/library/view/rust-atomics-and/9781098119430/ https://www.oreilly.com/library/view/rust-atomics-and/978109... > Features like Coroutines. This RFC is 7 years old now. We haven't been idling around for 7 years (either on that feature or in general). We've added asynchronous functions (which whole ecosystems and frameworks have arisen around), traits that can include asynchronous functions (which required extensive work), and many other features that are both useful in their own right and needed to get to more complex things like generators. Some of these features are also critical for being able to standardize things like `AsyncWrite` and `AsyncRead`. And we now have an implementation of generators available in nightly. (There's some debate about whether we want the complexity of fully general coroutines, or if we want to stop at generators.) Some features have progressed slower than others; for instance, we still have a lot of discussion ongoing for how to design the AsyncIterator trait (sometimes also referred to as Stream). There have absolutely been features that stalled out. But there's a lot of active work going on. I always find it amusing to see, simultaneously, people complaining that the language isn't moving fast enough and other people complaining that the language is moving too fast. > Function traits (effects) We had a huge design exploration of these quite recently, right before RustConf this year. There's a challenging balance here between usability (fully general effect systems are complicated) and power (not having to write multiple different versions of functions for combinations of async/try/etc). We're enthusiastic about shipping a solution in this area, though. I don't know if we'll end up shipping an extensible effect system, but I think we're very likely to ship a system that allows you to write e.g. one function accepting a closure that works for every combination of async, try, and possibly const. > Compile-time Capabilities Sandboxing against malicious crates is an out-of-scope problem. You can't do this at the language level; you need some combination of a verifier and runtime sandbox. WebAssembly components are a much more likely solution here. But there's lots of interest in having capabilities for other reasons, for things like "what allocator should I use" or "what async runtime should I use" or "can I assume the platform is 64-bit" or similar. And we do want sandboxing of things like proc macros, not because of malice but to allow accurate caching that knows everything the proc macro depends on - with a sandbox, you know (for instance) exactly what files the proc macro read, so you can avoid re-running it if those files haven't changed. > Rust doesn't have syntax to mark a struct field as being in a borrowed state. And we can't express the lifetime of y. > Lets just extend the borrow checker and fix that! > I don't know what the ideal syntax would be, but I'm sure we can come up with something. This has never been a problem of syntax. It's a remarkably hard problem to make the borrow checker able to handle self-referential structures. We've had a couple of iterations of the borrow checker, each of which made it capable of understanding more and more things. At this point, I think the experts in this area have ideas of how to make the borrow checker understand self-referential structures, but it's still going to take a substantial amount of effort. > This syntax could also be adapted to support partial borrows We've known how to do partial borrows for quite a while, and we already support partial borrows in closure captures. The main blocker for supporting partial borrows in public APIs has been how to expose that to the type system in a forwards-compatible way that supports maintaining stable semantic versioning: If you have a struct with private fields, how can you say "this method and that method can borrow from the struct at the same time" without exposing details that might break if you add a new private field? Right now, leading candidates include some idea of named "borrow groups", so that you can define your own subsets of your struct without exposing what private fields those correspond to, and so that you can change the fields as long as you don't change which combinations of methods can hold borrows at the same time. > Comptime We're actively working on this in many different ways. It's not trivial, but there are many things we can and will do better here. I recently wrote two RFCs in this area, to make macro_rules more powerful so you don't need proc macros as often. And we're already talking about how to go even further and do more programmatic parsing using something closer to Rust constant evaluation. That's a very hard problem, though, particularly if you want the same flexibility of macro_rules that lets you write a macro and use it in the same crate. (Proc macros, by contrast, require you to write a separate crate, for a variety of reasons.) > impl<T: Copy> for Range<T>. This is already in progress. This is tied to a backwards-incompatible change to the range types, so it can only occur over an edition. (It would be possible to do it without that, but having Range implement both Iterator and Copy leads to some easy programming mistakes.) > Make if-let expressions support logical AND We have an unstable feature for this already, and we're close to stabilizing it. We need to settle which one or both of two related features we want to ship, but otherwise, this is ready to go. > But if I have a pointer, rust insists that I write (*myptr).x or, worse: (*(*myptr).p).y. We've had multiple syntax proposals to improve this, including a postfix dereference operator and an operator to navigate from "pointer to struct" to "pointer to field of that struct". We don't currently have someone championing one of those proposals, but many of us are fairly enthusiastic about seeing one of them happen. That said, there's also a danger of spending too much language weirdness budget here to buy more ergonomics, versus having people continue using the less ergonomic but more straightforward raw-pointer syntaxes we currently have. It's an open question whether adding more language surface area here would on balance be a win or a loss. > Unfortunately, most of these changes would be incompatible with existing rust. One of the wonderful things about Rust editions is that there's very little we can't change, if we have a sufficiently compelling design that people will want to adopt over an edition. > The rust "unstable book" lists 700 different unstable features - which presumably are all implemented, but which have yet to be enabled in stable rust. This is absolutely an issue; one of the big open projects we need to work on is going through all the existing unstable features and removing many that aren't likely to ever reach stabilization (typically either because nobody is working on them anymore or because they've been superseded).
- iTokio 2y agoRust mission was already a difficult mix between performance, safety and expressiveness, then the project lost its “founder mode” when Mozilla disengaged, and the original core team mostly left, so no wonder progress slowed down. I personally think that’s it’s better than going down the wrong path.
- olivierduval 2y ago> Most crates I use - like human-size or serde don't need any special capabilities to work. So we don't need to worry so much about their authors "turning evil" and adding malicious code to our software well... :-( Actually, it's obvious that some authors might "turn evil" dumbly, by abusing some kind of priviledged permissions. By chance, these kinds of supply-chain risks are "easily" identified because 1) the permissions are an "easy" risk indicator, so you can priorize either to pin the version library (after validating it) or validate the new version 2) not so many libraries will use these permissions so you "have time" to focus on them 3) in these libraries, the permissions will tell you what system call/bad effects is possible, so will allow you to narrow even more the scope of investigation So, IMHO, permissions are not really the end of all but only a tiny step. The real problem is "how can human-size be used to subvert the program ?" For example: what is happening if the returned size "forget" or "add" 100 bytes to files bigger than 1 KB ? As a remininder, STUXNET was about some speed a tiny bit faster than planned and shown...
- alkonaut 2y agoIs there a known ratio of crates that use unsafe to ones that don't? It feels like most nontrivial crates would often need some unsafe. But a system like this might create a scenario where crates offload some of their unsafe code into separate crates so they need updating less frequently (Much like the blah-sys versus blah crates).
- selfmodruntime 2y ago> It feels like most nontrivial crates would often need some unsafe As a frequent contributor to a number of crates, this isn‘t really true. Also, most popular crates actively deny use of unsafe.
- saghm 2y agoI suppose this depends on your definition of "nontrivial", but I don't think most would, unless you count the fact that some stuff in std is implemented with unsafe under the hood. The only times I've ever needed to use unsafe Rust code in 5~ years of writing it professionally was for interfacing with a vendor-specific C library, and that was only for the wrapper around it; the rest of the code didn't need to use unsafe.
- alkonaut 2y ago> most uses of unsafe would also require explicit whitelisting. I think this is probably where all proposed whitelist/capability proposal discussions end. It's going to be too many crates that are in that category for it to be useful. A good first step (not sure if it's already taken tbh) would be to at least sandbox build execution. So that an attacker can't execute arbitrary code when your app is compiled.
- dietr1ch 2y agoMarking fixed stack size (and maybe even with an actual bound) would be helpful to ensure the tail-call optimisation is being done. I don't think any language helps verifying that., and even in the ones that require it by spec, it's unclear if it's happening. Maybe you didn't really wrote a tail-recursive function because of a helper that you expected to be inlined. I guess it's easy to notice if you try to blow the stack in a unit test though.
- aapoalas 2y agoGuaranteed tail-calls with the `become` keyword have been moving forward recently.
- josephg 2y ago> Marking fixed stack size (and maybe even with an actual bound) would be helpful to ensure the tail-call optimisation is being done. Yeah, it seems like a pretty easy feature to add. The compiler can pretty easily calculate the maximum stack size for every (bounded) call stack. It seems super useful to compute & expose that information - especially for embedded devices.
- johan_felisaz 2y agoThe section on comp time is written in a way which makes you think that zig invented the concept. It slightly irritated the lisper in me... Great article apart from that.
- josephg 2y agoAuthor here. Plagiarism is the most sincere form of flattery. I've never used lisp, but its nice to know that good ideas do, sometimes, eventually make their way into mainstream languages.
- lispm 2y agoit's similar, but Lisp was rarely "batch first" or "batch only", it was already coming from 100% interactivity and then adding compilation as subsystem. So running code during compilation is the default, for example with Lisp macros, which are normal functions. The software being compiled can add arbitrary code to the compilation environment. The traditional idea "compiled language" usually means a language designed for mostly batch compilation -> the compiler is not a part of the (potential) execution runtime. "compile time" and "run time" are not the same. In Lisp it is allowed to be the same.
- LetMeLogin 2y agoI stopped reading at "Like the first iPhone - which was amazing by the way." That phone couldn't even send MMS.... You had to jailbreak it to be able to do normal stuff that the phones could do for ages back then.
- gyre007 2y agoOne of the things that hit me when I was picking up Rust was that I felt like it had every imaginable feature one could think of - I dont know if Rust team said no to anything (yes I know they obviously must’ve done) - and yet people wanted more and more (some justifiably, others less so) as the language “felt” incomplete or that the features thatd be used by 2% of devs are totally necessary in the language that is “understood” by 1% of developer populace. I’m not saying the author is wrong here, just pointing out how a complex language somehow needs to be even more complicated. Spoiler: it doesn’t. Zig is simpler, arguably faster, with much less drama in the community. I wish more funding went to Zig.
- arresin 2y ago> I wish more funding went to Zig. Unfortunately that attracts the worst types. And their crapness and damage potential is sometimes not realised until it’s way too late.
- simonask 2y agoI'm curious, what drama in the Rust community are you referring to? I see some drama associated with Rust, but it's usually around people resisting its usage or adoption (the recent kerfuffle about Rust for Linux, for example), and not really that common within the community. But I could be missing something? Zig is great, but it just isn't production ready.
- chrisco255 2y agoOn drama: https://users.rust-lang.org/t/why-is-there-so-much-mismanagement-in-the-rust-foundation-and-core-team/94822 https://users.rust-lang.org/t/why-is-there-so-much-mismanage... Also, Zig is set to release 1.0 beta in November.
- simonask 2y agoI think the replies in that thread actually do a good job of describing how it is a bit overblown. As for Zig, I hope they make it. I think I kind of see why people are excited about it, but fundamentally the reason I'm not super hyped is that it doesn't seem to really enable anything new. It's far more expressive than C, but it doesn't make it easier to manage inherent complexity (to my understanding - haven't played with it a lot).
- csomar 2y ago> You can't tell that something is borrowed until you try to compile your program. (Aside: I wish Rust IDEs made this state visible while programming!) I am not sure what the OP is using, but with LSP I do get the error message in my editor (nvim) before any compiling (though am pretty sure some checking in happening in the background). > Compile-time Capabilities Not sure how this makes any sense when Rust compiles to multiple targets. Should all libraries become aware of all the "capabilities" out there. Also, this already can be implemented using features and keep things minimal. > Comptime I can't make sense of what the OP issue is here. > Make if-let expressions support logical AND. Its so simple, so obvious, and so useful. This should work: if let Some(x) = some_var && some_expr { } The example makes no sense.
- raverbashing 2y agoYou know, I agree And there's a lot of things that are weird or clunky I honestly don't "get" the "no classes, just struct methods thing" and while, sure, C++ is kinda like that, but the ergonomics are weird. I'd much rather have the class/methods declaration as most languages do Lifetimes are good but the implementation is meh. Most cases could do with a default lifetime. Copy/borrow strictness is good to think about but in most cases we don't care? Copy should probably the default and then you borrow in special cases
- tommiegannert 2y ago> Rust doesn't have syntax to mark a struct field as being in a borrowed state. > ast_nodes: Vec<&'Self::source str>, Oh, that would be neat to replace the https://github.com/tommie/incrstruct https://github.com/tommie/incrstruct I wrote for two-phase initialization. Unlike Ouroboros and self_cell, it uses traits so the self-references can be recreated after a move. Whether it's a good idea, I don't know, but the magic Ouroboros applies to my struct feels wrong. But I say that as someone coming from C++. > if let Some(x) = some_var && some_expr { } Coming from Go, I was surprised that something like if let Some(x) = some_var; expr(x) { } isn't a thing.
- lifthrasiir 2y ago`if some_var.is_some_and(|x| some_expr)` is the current way to do that. It is less flexible and doesn't actually bind `x` into the conditional body (hence the proposal) but works today.
- josephg 2y agoYeah, but I almost always want to pattern match out the value when I do that. As I said in the post you can also write this: if let (Some(x), true) = (my_option, expr) { But then it doesn't short-circuit. (expr is evaluated in all cases, even when the optional is None). Both approaches are also weird. It'd be much better to just fix the language to make the obvious thing work.
- lifthrasiir 2y agoI personally use two conditionals for such case. Yes, I might have written Rust too long to say this but it is more like a minor ergonomic fix and any solution should be generalizable into other use cases. The eventually accepted syntax, `if let PAT = EXPR {&& EXPR}` [1], is okay by itself but not (yet) generalized and that's my current complaint about it. The whole `{let PAT = EXPR &&} EXPR` should have been a valid expression in my opinion. (This exact suggestion is not in the RFC, the closest would be making `let PAT = EXPR` a boolean expression which really looks like a mistake.) Maybe I should check whether this was ever suggested... [1] https://rust-lang.github.io/rfcs/2497-if-let-chains.html https://rust-lang.github.io/rfcs/2497-if-let-chains.html
- bjackman 2y agoRust isn't an Exciting New Language any more. It's in the "work towards widespread adoption" phase. Slower feature development is natural and healthy, the stakes are high, mistaken design choices are much more harmful than low velocity at this point. I'm not excited about Rust because of cool features, I'm excited because it's a whole new CLASS of language (memory safe, no GC, production ready). Actually getting it into the places that matter is way more interesting to me than making it a better language. That's easier to achieve if people are comfortable that the project is being steered with a degree of caution.
- josephg 2y agoMaybe. But javascript is arguably in that phase of its life as well, and JS has had a oodles of wonderful new features added in the last decade. Features like the spread operator, generator functions, async, arrow functions, leftpad, a new Date, and so on. The list of significant new features is endless. All that, despite JS being much older than rust, and much more widely used. Javascript also has several production implementations - which presumably all need to agree to implement any new features. Javascript had a period of stagnation around ES5. The difference seems to be that the ecmascript standards committee got their act together.
- gary17the 2y agoJavascript has a quite different use-case audience than Rust. As an example, try to convince a guy like Linus Torvalds to officially support a particular PL for Linux kernel development, when his absolute priority (quite rightly so) is predicable, performant and portable code generation on the same level as raw C, with ease-of-use of a PL not being even a distant second, if considered at all. JavaScript does not really have to live up to those kinds of challenges. The assumption that "[Rust] stagnation" is due to some kind of "Rust committee inefficiencies" might be incorrect.
- josephg 2y agoAuthor here. > Javascript has a quite different use-case audience than Rust. Eh. That sounds like a "just so" explanation to me. Linus Torvalds doesn't work on the rust compiler. I think I could make much more convincing arguments that javascript should move slower than rust - given there's so many large language runtime projects. (V8, Safari, Javascript, Node, Deno, Bun, etc etc). But evidently, that isn't the case. I'm open to the reason for rust's slow development being that the language developers want the language to move slowly. Thats fine. But, I personally don't want that. I've been waiting for generators to ship for 7 years. Or TAIT to appear - again, for years. I'd much rather rust to move faster. Of course I attribute all of this to the process & team which makes these decisions. What else is there? What else has any affect on the development of rust?
- nikolay 2y agoIf functions are "fn", then coroutines should be "co". In terms of verbosity, Rust turned into Java.
- eterevsky 2y agoI would gladly switch to a Rust fork without async. Even though this article is not about async per se, it’s clear that async makes most of the described problems worse.
- lifthrasiir 2y agoIsn't that trivial? Just use Rust but reject any occurrence of `async` or `await` in your code or dependencies. Rust doesn't even force the use of async code for certain features in its standard library.
- simon_o 2y agoThe problem is the ecosystem split and the decades of man hours of churn caused in libraries and user code – that's time and effort that could have been spent on making those dependencies better. This applies to both suggestions ("fork" and "don't use it").
- lifthrasiir 2y agoSo does forking, as the parent originally suggested.
- deleted 2y ago[deleted]
- M4Luc 2y agoAnd use which first class libs? IO related libs are almost all based on Tokio. I mean I'm happy that at least there's some consent regarding the runtime. But you can't undo the decisions for going async (instead of green threads) that easily.
- josephg 2y agoAuthor here. I think async is a great feature to have - but I can't help but wonder if you're right. It might just be case of timing, but it seemed like once async was in the works, work on the rest of the language ceased. For awhile there all energy was poured into bikeshedding over how async would work. And I don't know if anyone is super happy with the result. Pin is a mess. Async functions still return anonymous objects - which cause all sorts of problems. And there still aren't coroutines in the language, even though async functions are implemented internally using coroutines anyway. If we could go back in time and have the rust project decide to never implement async, I wonder what rust would look like today. There's a good chance the language & compiler would be much nicer as a result.
- gary17the 2y ago> The rust RFC process is a graveyard of good ideas. I actually have quite an opposite view: I think the Rust core team is 100% correct to make it very hard to add new "features" to the PL, in order to prevent the "language surface" from being bloated, inconsistent and unpredictable. I've seen this happen before: I started out as a Swift fan, even though I have been working with Objective-C++ for years, considered it an awesome powerhouse and I did not really need a new PL for anything in particular in the world of iOS development. With time, Swift's insistence on introducing tons of new language "features" such as multiple, redundant function names, e.g., "isMultiple(of:)", multiple rules for parsing curly braces at al. to make the SwiftUI declarative paradigm possible, multiple rules for reference and value types and mutability thereof, multiple shorthand notations such as argument names inside closures, etc. - all that made me just dump Swift altogether. I would have to focus on Swift development exclusively just to keep up, which I was not willing to do. Good ideas are "dime a dozen". Please keep Rust as lean as possible.
- formerly_proven 2y ago> Please keep Rust as lean as possible. Alternatively: Rust is already the Wagyu of somewhat-mainstream PLs, don't keep adding fat until it's inedible.
- deleted 2y ago[deleted]
- josephg 2y agoAuthor here. I hear what you're saying. But there's lots of times while using rust where the language supports feature X and feature Y, but the features can't be used together. For example, you can write functions which return an impl Trait. And structs can contain arbitrary fields. But you can't write a struct which contains a value returned via impl Trait - because you can't name the type. Or, I can write if a && b. And I can write if let Some(x) = x. But I can't combine those features together to write if let Some(x) = x && b. I want things like this to be fixed. Do I want rust to be "bigger"? I mean, measured by the number of lines in the compiler, probably yeah? But measured from the point of view of "how complex is rust to learn and use", feature holes make the language more complex. Fixing these problems would make the language simpler to learn and simpler to use, because developers don't have to remember as much stuff. You can just program the obvious way. Pin didn't take much work to implement in the standard library. But its not a "lean" feature. It takes a massive cognitive burden to use - to say nothing of how complex code that uses it becomes. I'd rather clean, simple, easy to read rust code and a complex borrow checker than a simple compiler and hard to use language.
- louismerlin 2y agoIf I were to rewrite Rust, I'd probably go the route of less features, not more. Make it 70% of Rust in 10% of the code, similarly to what QBE[0] is doing with LLVM. You'd probably be able to achieve that if you remove macros and some of the rarely-used features. [0]: https://c9x.me/compile/ https://c9x.me/compile/
- lifthrasiir 2y agoNot to downplay QBE, but the initial goal of QBE was to provide 90% of the performance in 10% of the code, until it was changed to 70%. You generally don't know how much of Rust (or anything else) is possible without actually trying.
- chkhd 2y agoI wonder how soon they will arrive at 80%/20%.
- uneekname 2y agoI am relatively new to rust (only written a couple thousand lines, haven't fully grokked "idiomatic" rust, etc.) and I feel like I've run into these and similar warts many times. It is weird to lookup, say, coroutines in Rust to learn that everyone seems to agree they should exist, but they won't anytime soon. For a language focused on "correctness" and ergonomics, I think the rust community should consider some backwards-incompatible changes in the name of a better language.
- mathw 2y agoThere have already been two sets of backwards-incompatible changes in Rust, and there's a third on the way in the 2024 Edition (unfortunately due out in early 2025). They tend to be relatively conservative, but that's because they want it to be easy to update your code, but there is stuff the team want to do that requires syntactic or semantic incompatibilities, so that's what that mechanism is for. It's a bit restricted on how much you can do because they do promise compatibility with older crates, but it seems to be working out pretty well and that compatibility promise is part of why it does work.
- hiimkeks 2y agoI think the first three items are "add effects, and do it right": Capabilities to IO can be done by letting IO functions interrupt and call an effect handler, and the caller can specify the effect handler and do access control in there. The whole Pin situation only exists because async/await was an afterthought and didn't work well with the existing language. async/await is an instance of effects. I'm excited to start playing with a language that has a good effect system. I am hoping on Ante, but would also like to try Roc at some point.
- deleted 2y ago[deleted]
- dathinab 2y agoIt's kinda strange how he complains first about a slow decision making process and then lists features which are not stabilized for reasons fully unrelated to the decision making. E.g. corutines are stuck because they have some quite hard to correctly resolve corner cases, i.e. in the compiler there isn't a full implementation you could "just turn on" but a incomplete implementation which works okay for many cases but you really can't turn on on stable. (At least this was the case last time I checked.) Similar function traits have been explicitly decided to not be stabilized like that for various technical reasons but also due to them changing if you involve future features. (Like async corotines.) Sure the part about return values not being associated types is mostly for backward compatibility but it's also in nearly all situations just a small ergonomics drawback. And sure there are some backward compatibility related designs which people have loved to do differently if they had more time and resources at the point the decision was made. But also most of them are related to the very early rust times when the team still was much smaller and there where less resources for evaluating important decisions. And sure having a break which changes a bunch of older decisions now that different choices can be made and people are more experienced would be nice. BUT after how catastrophic bad python2->python3 went and similar experiences in other languages many people agree that having some rough corners is probably better and making a rust 2.0. (And many of this things can't be done through rust editions!) In general if you follow the rust weekly newletter you can see that decisions for RFC acceptance, including for stabilization are handled every week. And sure sometimes (quite too often) things take too long, but people/coordination/limited-time problems are often harder to solve then technical problem. And sure some old features are stuck (corotines) and some but also many "feature gates" aren't "implemented stuck features" (but e.g. things which aren't meant to be ever stabilized, abandoned features, some features have multiple different feature gates etc.)
- mwcampbell 2y ago> a fully baked language - warts and all. Python 2.7 for life. I still wish the Python core team had abandoned the Python 3 experiment and gone with Python 2.x for life, warts and all. I learned to work with the warts, including the Unicode ones. I think a lot of us did.
- adastra22 2y agoDo it! I’d use this language.
- ephaeton 2y ago"Maybe I should fork the compiler and do it myself. Urgh. So many projects. If I could live a million lifetimes, I'd devote one to working on compilers." -- Maybe you are living a million lifetimes in parallel right now and this one is the one devoted to working on compilers? Get to it! :-)
- mplanchard 2y agoShouldn’t read this without also reading Josh Triplett’s comment in response on reddit. One of the core examples in this post is just plain wrong (mutexes), for example: https://old.reddit.com/r/rust/comments/1fpomvp/rewriting_rust/lozktuv/ https://old.reddit.com/r/rust/comments/1fpomvp/rewriting_rus... Edit: nevermind, comment is here too: https://news.ycombinator.com/item?id=41655268 https://news.ycombinator.com/item?id=41655268
- FrustratedMonky 2y ago"the coroutines RFC has lasted longer than World War 1 or 2" This sounds bad, but I wonder how many features have taken this long to include in other languages. Is this really as out of step as it sounds? There is the move-fast-break-things mentality, but is that how you want to design a language? Seems like we are missing some middle ground step, where there are good features, maybe even done, and stable, but they aren't getting worked into the main language. Maybe a decision making problem.
- binary132 2y agoWhen I look at the way C++ has been developed and implemented over the years, I can’t help but think that a relatively small and questionably sustainable group of compiler engineers, no matter how passionate (and people do burn out) cannot possibly hope to sustain development of Rust indefinitely, especially as the project’s complexity and convolutions continue to further complicate and convolve. The only reason C++ has been able to is that it has very extensive industrial sustenance behind at least two of its major compilers, and presumably they also help keep GCC up to par. I don’t know, maybe GCC can somehow set the standard for what Rust can hope to do over the years, but it seems like a minor miracle from the outside.
- jfyasdfwasdf 2y agoRust 2.0 wishlist: * Supports Unions (TypeScript, Flow, Scala3, Hare) * Supports GADTs * Capable of targeting both preemptive userland concurrency (go, erlang, concurrent Haskell, concurrent OCaml) and cooperative (tinygo, nodejs, async-python, async-rust) without code changes * Easily build without libc (CGO_ENABLED=0) * No Backwards compatibility promise - This eliminates geriatrics * Cleaner syntax, closer to Go, F#, or Python * Graph-based Borrow Checker * Add `try-finally` or `defer` support, `Drop` is too limiting, Async drop could help. * Fix Remaining MIR Move Optimizations and Stack Efficiency * Culture for explicit allocator passing like Zig * `.unwrap()` is removed
- gavinhoward 2y agoI explain how Rust missed the mark in [1]. [1]: https://gavinhoward.com/2024/05/what-rust-got-wrong-on-formal-verification/ https://gavinhoward.com/2024/05/what-rust-got-wrong-on-forma...
- epage 2y agoRE: Rust's pacing I've had a lot of talks with my management about that. For context, I'm on the Cargo team and have authored 11 RFCs (10 approved, 1 pending). I feel like a lot of the pacing feels slow because: - As the project matures, polishing whats there takes up a lot of effort - Conversely, hitting local maximas where things are "just good enough" that individuals and companies don't feel the need to put effort to doing the last leg of work. - Lack of coordinated teams (formerly Mozilla) doubling down on an idea to hash it out. Hopefully [Project Goals](https://rust-lang.github.io/rfcs/3614-project-goals.html https://rust-lang.github.io/rfcs/3614-project-goals.html) will help a little in this direction. - As the project has grown, we've specialized a lot more, making it harder to develop a cross-team feature. It takes finesse to recruit someone from another team to help you finish out a cross-team feature. It also doesn't help we've not done a good job developing the cross-team communication channels to make up for this specialization. Again, Project Goals are trying to improve this. In-person conferences starting back up has also been a big help. As for RFCs, we've been moving in the direction of choosing the level of process thats appropriate for a decision. Unsure how something will look? You just need approval from 2 members of the relevant team to start a nightly only experiment to flesh out the idea in preparation for an RFC. In Cargo, many decisions don't need wide input and are just team votes on an Issue. RFCs drag out when their isn't a someone from the team shepherding it through the process, the RFC covers too much and needs to be shrunk to better focus the conversation, too much is unknown and instead an experiment is needed, or its cross-team and you need to know how to navigate the process to get the vote done (we want to improve this). As for things being approved but not completed, thats a "we need more help" problem usually.
- pdimitar 2y ago> As for things being approved but not completed, thats a "we need more help" problem usually. You know, I would LOVE working on Rust (not just with Rust) and be a part of some of the core team(s). But my impression is that nobody truly has any powerful agency over things and even if you formulate a near-perfect and a PR to go with it, things would still end with several smarter people than me saying "Oh this looks really neat, we should ponder it more and test it further and merge it!" and then it never happens. That, plus I am not sure how is the job stability situation there.
- sam0x17 2y agoThese are actually great and I would gladly welcome these changes if they were implemented in stable. My wishlist: * allow const fns in traits * allow the usage of traits in const exprs. This would allow things like using iterators and From impls in const exprs, which right now is a huge limitation. * allow defining associated type defaults in traits. This can already be worked around using macros somewhat effectively (see my supertrait crate) but real support would be preferable. * allow eager expanding of proc macro and attribute macro input, perhaps by opting in with something like `#[proc_macro::expand(tokens)]` on the macro definition. Several core "macros" already take advantage of eager expansion, we peasants simply aren't allowed to write that sort of thing. As a side note, eager expansion is already possible for proc and attribute macros designed to work _within proc macro crates_, for example this which I believe is the first time this behavior was seen in the wild: https://github.com/paritytech/substrate/blob/0cbea5805e0f4edcf8a3a70135b4d8eabc2db06f/frame/support/procedural/src/lib.rs#L971-L982 https://github.com/paritytech/substrate/blob/0cbea5805e0f4ed... * give build.rs full access to the arguments that were passed to cargo for the current build. Right now we can't even tell if it is a `cargo build` or a `cargo doc` or a `cargo test` and this ruins all sorts of opportunities to do useful things with build scripts * we really need a `[doc-dependencies]` section in `Cargo.toml` * give proc macros reliable access to the span / module / path of the macro invocation. Right now there are all sorts of projects that hack around this anyway by attempting to locate the invocation in the file system which is a terrible pattern. * allow creating custom inner attributes. Right now core has plenty of inner attributes like `#![cfg(..)]` etc, and we have the syntax to define these, we simply aren't allowed to use custom attribute macros in that position * revamp how proc macro crates are defined: remove the `lib.proc-macro = true` restriction, allowing any crate to export proc macros. Facilitate this by adding a `[proc-macro-dependencies]` section to `Cargo.toml` that separately handles proc-macro-specific dependencies. Proc macros themselves would have access to regular `[dependencies]` as well as `[proc-macro-dependencies]`, allowing proc macro crates to optionally export their parsing logic in case other proc macro crates wish to use this logic. This would also unblock allowing the use of the `$crate` keyword within proc macro expansions, solving the age old problem of "how do I make my proc macro reliably refer to a path from my crate when it is used downstream?" * change macro_rules such that `#[macro_export]` exports the macro as an item at the current path so we can escape from this ridiculousness. Still allow the old "it exports from the root of the current crate" behavior, just deprecate it.
- Havoc 2y agoThe drama around rust leadership and also in kernel has me more spooked tbh. It’s more of a threat to the long term viability of the lang. Flaws in a language are to some extent expected and can be worked around. Languages like C++ and python are wildly successful and don’t think anyone would call them perfect. The dependence point is valid but not sure that is easily solvable in general. Doesn’t seem like a rust issue. See npm and python pip - blind trust is par for the course except in very rigorous environments
- Avi-D-coder 2y agoyep,i agree on all of this and suspect a large portion of long timers do too. Some one just has to do it.
- OnorioCatenacci 2y agoFrom the examples he's mentioned, it sounds like there's quite a bit of [bike shedding] (https://en.wikipedia.org/wiki/Law_of_triviality https://en.wikipedia.org/wiki/Law_of_triviality) in the process for RFC's in Rust. That's a problem when you've got lots of smart people trying to help.
- deleted 2y ago[deleted]