And this blog post from someone who did spend a lot of time working with async rust: https://tomaka.medium.com/a-look-back-at-asynchronous-rust-d...
And this blog post from someone who did spend a lot of time working with async rust: https://tomaka.medium.com/a-look-back-at-asynchronous-rust-d...
It may be the case that there's no good way to solve them, but that doesn't mean that they aren't problems and it doesn't really help to say that people who highlight them are totally wrong and don't know what they're talking about.
That said I think your second link does a much better job of explaining the issues than this post does.
Apart from requiring a safe zero-copy io-uring abstraction to use a buffer pool instead of "bare" references, Rust's polling+cancellation model is fantastic. It's incredibly convenient to be able to externally time out and abort any Future, without needing to pass contexts/tokens and/or needing every I/O operation to have an explicit timeout option.
It's annoying when conscious small trade-offs are framed as fatal flaws (like the title of TFA). In the case of the cancellation model the "doesn't work" is that a safe abstraction is not entirely zero-cost. But when you use async in JS, C#, or Golang, you already have unavoidable heap allocations and memcpys (and another set of difficulties with cancellation). Rust's worst-case flaw is comparable to a normal mode of operation in a few other async languages. The scale of the issue is overblown, and its benefits are overlooked.
> In 2017, I said that “asynchronous Rust programming is a disaster and a mess”. In 2021 a lot more of the Rust ecosystem has become asynchronous – such that it might be appropriate to just say that Rust programming is now a disaster and a mess. As someone who used to really love Rust, this makes me quite sad.
I imagine withoutboats read both and was pretty upset.
I am tempted from time to time to try Rust, but in the end, I don't think it provides enough benefits for me to consider it. I like high-level, and when I am going low-level, I don't want to be hand-cuffed. It seems with Rust, I am paying all the time just for the ability to go into hand-cuffed low-level mode.
Most of the time, particularly if you're not writing libraries, Rust feels like a dialect of Python that wants to help you get things right.
I assume that having a Rust library of something is a good thing. The question for me is: How easy and natural and quick is it to express a concept as a library in Rust?
1. Do you like strong type systems? If so, Rust us great! If you really would e itching for some python or JS, it may bother you, even though the Rust type inference really makes it a non-issue.
2. Do you care about allocations? One could be cheeky and rephrase it as "do you care about performance", but caring about allocations is one of the more advanced optimization concerns and GCed languages can have great performance if you dont hit their pathological cases. But the thing about Rust is that you have as much control as possible to avoid allocating. Entire libraries can allocate nothing more than temporary stack variables, with their primary data being lifetime constrained references the user passes in.
2.5 if you dont care about allocations, then does `Rc<Foo>` bother you? There are very easy escape hatches when you _just don't care_ if that thing is shared and don't want to deal with lifetimes. But Rust _lets you choose_.
To me, its a pleasure to use.
So yeah, Rc<Foo> and stuff like that would bother me, because most of the time, these things are rather peripheral to what I am implementing.
I feel that, when performance is really really important, it is more important to be able to generate code on the fly, and I don't think Rust supports that.
But I haven't tried out ownership in Rust. I will have to work with it for a while to see if it bothers me or not.
Sometimes Rust is handcuffs, sometimes it is guardrails, sometimes it is a rollercoaster track.
It is impossible to tell without more information. You and the other guys are asserting things with basically no knowledge of the other's context.
I'd still recommend learning Rust though. I find the way (the clean ways, not the ugly ways like Weak/Cell/etc.) it forces you to structure your programs is a very useful pattern when dealing with unrigid code like in C or C++, since its performance is near those languages. Then when coding C/C++ you can just break out of that pattern when you need to (e.g. self-referential structs).
BTW, what languages do you usually work with? I've been eyeing up Zig since it's nearly adjacent to C, but I'm waiting until stabilization.
I need to break out of that Apple silo though for an important project of mine, so I am looking for alternatives. I was looking at zig, too! It seems very promising, and comptime seems like a great idea. I am considering both Rust and Zig for generating libraries in WebAssembly.
I think I will mostly go with TypeScript for my project, it seems undogmatic and highly productive, and Turbo Pascal was my second language after Quick Basic, so I like its origins :-)
Ah, you're one of those people. Sure. :-)
If you care about developer speed and security but don't care about correctness or performance you can rely on someone's else implementation and write higher level code (eg. use node and offload low level security considerations to node).
If you care about developer speed and performance but don't care about correctness or security use a low level unbounded language (eg. write C and triple check your code)
If you care about security, correctness and performance but don't care about developer speed, use Rust.
To be frank I find the point about developer speed in Rust to be a bit exaggerated, it's pretty high level and the tooling is pretty great.
- Compiler speed is a bit hit or miss - Debugging life cycles definitely take some time, but with time you get the hang of it and you can quickly copy paste previous solutions to the current problem. - You save a significant amount of developer time by fixing things alerted by the compiler instead of finding errors at runtime
All things considered Rust is definitely the language I feel more productive in (before it used to be Haskell).
Oftentimes considerations about hiring / collaborating with other developers take the precedence over security, correctness and performance.
Right now I'm maintaining a node.js project, 2 Python projects and a Rust project - mainly because node.js and Python worked best with those teams and the Rust one is a solo project.
I am thinking TypeScript might give the biggest bang for the buck: * You have the widest possible reach via web apps & Electron * You have an eval/Function object for compiling code on the fly * You can embed low-level code via WebAssembly (and here Rust might be relevant for producing that WebAssembly) * If you need access to your TypeScript libraries on mobile, you can still do that via embedding a hidden WebView.
Rust has a long learning curve that most people won’t make it through. For them, they might feel the language is slow to developenin because they haven’t gotten to the point where they are “thinking” in Rust.
As a Haskeller, you are well suited to learn Rust; due to their similar ML lineage (the original Rust compiler was written in OCaml), Rust and Haskell make some similar design considerations. I’d say one thing Rust does right is take a lot of the things that make Haskell safe and make them fit in an imperative language.
GP's statement "If you care about security, correctness and performance but don't care about developer speed, use Rust." threw me a little off here. Because, Standard ML is very quick and easy to develop in. So should Rust not inherit that property?
It's possible to write C++ or Java or Haskell in Rust but then compiler becomes your enemy and you fight it at every turn.
The Rust compiler and specifically the borrow checker help you write code that works the first time, which is a property Haskell famously exhibits. In order to get there, sometimes an involved conversation with the borrow checker or type checker is needed. What this means is sometimes you might spend a good long while figuring out a particular lifetime and ownership annotation in order to satisfy the borrow rules. Another implication is that sometimes the way you've architected your code is just plain wrong as far as the borrow checker is concerned. Sometimes it's hard to tell when you just need to add a particular annotation to your code to make it work, or if you actually need to rethink everything entirely. For example, if you go writing a doubly linked list in Rust thinking you'll use pointers, that's just the wrong way to go about it in Rust world, so rather than trying to force that style of code, doing things the Rust way (using Rc<RefCell<T>>>) will yield better results.
But once you get your code to compile, things generally work in a sense that the code will never fall victim to a whole class of bugs that frequent code written in other languages (segmentation faults, use after free, memory leaks, dangling pointers, etc.) You just won't see these things in safe, idiomatic Rust code.
And that leads me to developer speed. Once you and the borrow checker are on the same page, it's like night turned to day. Early when I first started writing Rust, I would spend most of my time dealing with borrow checker errors. Now that I know what the borrow checker expects, and I've internalized all the strange syntax and edge cases, the borrow checker fades into the background and I can code in Rust just about as fast as I can in TypeScript.
As a Haskeller, I expect you might approach writing Rust code in a functional style, and I think this would serve you well. The general approach that newbies take in Rust and which finds strong resistance by the Rust compiler is copious use of passing references for mutation, and creating a rat's nest of pointer references. This style of coding doesn't go over well in Rust, and unfortunately a lot of coders practice this because it's permitted by their native language.
Instead, it's better to lean into type checking and actually use the type checker to save you from having to write a lot of code. Take advantage of immutability and referentially transparent function. Make heavy use of pattern matching and Maybe monads cough I mean Option<T>. We don't use that word in Rust. Haskellers get all of this.
Things of course would be different should the client insist on implementation done in Rust but so far not a single client of mine ever mentioned using this language.
The problem is that most likely those mediocre C++ developers won't be able to write any Rust at all.
If you do have good C++ developers, you're also probably better off sticking to well-established and battle-proven C++.
So the use case for Rust remains niche. It's a way to attract the programming language nerd that knows more about Haskell than he does about systems programming. Maybe not exactly the best fit? But worth trying if you want to differentiate yourself from the competition.