Comment by xedrac
8 hours ago
I loved working in Haskell for a few years. I wasn't actively looking it, but the opportunity just sort of landed in my lap. It was exciting and mentally stimulating. But the unfortunate fact is, I am easily twice as productive in Rust as I am Haskell, even after 3 years of nothing but Haskell. There are more pitfalls in Haskell that you have to just know how to avoid. It can be very difficult to digest as the language can be borderline write-only at times, depending on the author of the code. The tooling is often married to Nix, which is it's own complex beast. And it feels like language extensions are all over the place. Cabal files are not my favorite. And the compiler errors take some time to get get used to.
Pretty surprising -- I had much the opposite experience.
On our last product, we decided to start switching from Typescript to Rust on the backend because we got tired of crashes. I consider that to be one of the greatest technical mistakes I've made ever, as our productivity slowed massively. I'll just share two time-draining issues that only occur in Rust: (1) Writing higher-order functions (e.g.: a function to open a database connection, do something, and then close it -- yes, I know you can use RAII for this particular example), which is trivial in Haskell and TypeScript and JavaScript and C++ and PHP, turned out to be so impossible in Rust [even after asking Rust-expert friends for help], that I learned to just give up and never try, though it sometimes worked to write a macro instead. (2) It's happened many times that I would attempt a refactoring, spend all day fixing type errors, finally get to the top-level file, get a type error that's actually caused somewhere else by basic parts of the design, and conclude the entire refactoring I had attempted is impossible and need to revert everything.
On top of that, Rust is the only modern language I can name where using a value by its interface instead of its concrete type lies somewhere between advanced and impossible, depending on what exactly you're doing.
I came away concluding that application code (as opposed to systems or library code) should, to a first approximation, never be written in Rust.
I appreciate Rust for making affine types mainstream, and having at least the C++ community start caring about security, even if half hearted.
However I share your conclusion, outside scenarios where having automated resource management as the main approach is either technically impossible, or a waste of time trying to change pervasive culture, I don't see much need for Rust.
In fact those that write comments about wanting a Rust but without borrow checker, the answer already exists.
I think Rust would be fine for application code if it kept the borrow checker, but had greater allowance for dynamically-sized variables, or even garbage collection. The reason calling things through an interface is so tough in Rust is because doing so requires having a pointer to a value of unknown size, which involves either heap allocation or alloca(), neither of which are very happy in Rust. Many of the other things I complained about are also downstream of this decision. Affine types are useful both in high-level state management as well as in low-level memory management. But it's Rust's focus on static memory layout that really cements it as a low-level systems language, not its inclusion of borrowing.
Way back as an undergrad in 2011, I contributed to Plaid, a JVM language whose main feature is based on affine and linear types. I'm one of the very few people in the world who knew what borrowing is before Rust had it. So I know first-hand that borrow-checking is perfectly compatible with garbage collection.
2 replies →
Maybe it depends on the application, but web servers are effortless with something like axum. Libraries can do a lot of heavy lifting to expose straightforward coding patterns. Never had any problems like you desribed with database connections and such. In rust with db pools things just work and get closed on drop etc. I would never even consider making a higher order function for that.
Only other language that I think gets close to rust ergonomics is Kotlin, but it suffers from having too many possibilities for abstractions.
Depends very much on the market.
On my line of work we don't do Web servers from scratch, we use lego pieces like with enterprise integrations.
Think Sitecore, Dynamics, Sharepoint, Optimizely, Contentful, SAP, Mongolia, Stripe, PayPal, Adobe, SQL Server, Oracle, DB2,.....
Axum offers very little over existing .NET, Java, nodejs SDKs provided by those vendors.
(1) Higher order functions are pretty much the same as all the other languages you mentioned, using closure syntax? What was the problem you ran into?
(2) In such situations the compiler (type system or borrow checker) is telling you that what you wanted to do has hidden bugs, and therefore refuses to compile. Usually that's a good thing.
(3) &dyn Trait
(1) Oh sure, the syntax is easy. Getting it to borrow-check is somewhere between insane and impossible. As I said, I've had friends who are actual Rust experts give up trying.
(2) No, it stems from a compiler limitation (imposed in large part by the need for static memory layout), not because there's anything intrinsically buggy about doing this.
(3) Look up "dyn-compatibility", for the largest, but not the only, problem with doing this.
2 replies →
That's pretty interesting. I was thinking about starting a new pet project and was considering doing it in Rust to learn as I never tried anything with it and after some small pocs I had the feeling it was too verbose to my taste, but wasn't sure it was just me and/or my lack of experience with Rust. Still, wonder if it's still worth it to give a shot considering other positive elements of the language.
It’s worth learning, in my opinion, but I’ve been writing it professionally for the better part of a decade, so my opinion may be a bit skewed.
It’s my favorite language to write, and it gets much easier over time. As a first approximation, if you’re doing something and it feels insanely difficult like the GP is talking about, try to think of a different way to do it rather than fighting it. There’s usually a way to do almost anything, but it’s more pleasant to lean into the grooves the language pushes you towards.
Rust is definitely very verbose. I think it's a fine choice -- probably even the best choice -- if you're doing systems code or if performance is your most important feature. If not, I would pass.
1 reply →
That is a very unusual Rust experience. I find "application code" very pleasant to write in Rust. Of course there are things that aren't as ergonomic in Rust as in other languages (e.g. callbacks) but that's true of pretty much any language.
I have heard this reaction from others before. One of the Rust expert friends I consulted with told me "I'm not convinced you're not trying to write Haskell-style code in Rust;" I told him the patterns I was struggling with were both trivial and common in Java.
The things I found quite difficult or impossible in Rust were to me pretty basic patterns for modularity and removing duplication that it's really shocking that these complaints are not more common.
I currently have but two hypotheses for why.
First, the second problem I mentioned only comes from using tokio, which causes your top-level program to secretly be using a defunctionalized continuation data type, derived from where exactly in other files you put your await's, that might not be Send. If you're not using tokio, you won't experience that issue.
Second...I was kinda told to just give up on deduplication and have lots of copy+pasted code. This raises the very uncomfortable hypothesis that Rust afficionados are some combination of people who came to Rust early and never learned traditional software design and don't know what they're missing, and people who were raised on traditional good software engineering but then got hit with Rust's metaphorical baseball bat of lack-of-modularity over and over until they got used to being hit with a baseball bat as a normal pain of life.
I don't like either of these explanations (esp. with tokio seeming quite dominant), so I'm awaiting an explanation that makes more sense. https://xkcd.com/3210/
14 replies →
Is the productivity 2x all across the board, or are there some parts that are less productive with Rust? Also, what do you mean by write-only?
>what do you mean by write-only?
I think they meant that in Haskell it is very easy to write externally unreadable code..