47 comments

[ 1.8 ms ] story [ 146 ms ] thread
> in applications that don’t require maximum resource efficiency and memory safety, adopting Rust in 2020 is irrational at best

which applications don't require memory safety?

(comment deleted)
Just have a cron job restart the service daily to fix all the memory leaks /s
(I know this is a sarcastic comment, but memory leaks are memory safe and Rust does not prevent them (though they do tend to be less common))
Presumably applications that are never exposed to unexpected input?
Multithreaded apps are exposed to unexpected timing. Memory safety there becomes a big deal.
> but in order to manage memory the way the borrow checker wants, the programmer is at best tempted, and at worst forced, to add complexity to the program.

This is a problem for newcomers because they have to adapt their way of thinking into Rust way of thinking. Once one develops a set of patterns and principles this is not an issue.

Companies who have large codebases in Rust tend to have praise for it enabling solutions that are much easier to reason with and work on then if they were developed in C++.

It is obvious the author has little to no experience in developing production software in Rust.

> It is obvious the author has little to no experience in developing production software in Rust.

Statements like these don’t necessarily speak for the user-friendliness of Rust or Rust itself. Safety? OK, cool. But for what cost?

I think the cost is roughly: "we force you to reason about, and account for safety in the code." Then given that this is now explicitly forced upon the developer, are Rust's constructs overly complex, or reasonably once someone gets over the learning curve? The alternative is using a managed runtime, which probably should be the default for most programmers. But for those that are doing systems programming, we absolutely need something "like Rust." The memory access patterns need to be explicit.
Personally I think the type system (via traits and genetics) makes it really easy to build abstractions with low costs and friendly APIs, which makes composing good software that runs faster much easier.

There seems to be a class of developer that's been brainwashed into thinking generic programming is bad. It's pretty damn great when your type system is well designed.

I'm interested in Rust's future, but not a Rust developer myself.

The author's argument is pretty straight-forward: Rust's borrow-checker makes for complex code, so you should think carefully whether your application is resource-constrained enough to merit using Rust. If not, you should consider using a memory-managed language.

He's pointing this out as a contrasting point to projects rewriting in Rust, which is what naturally happens when a new language starts going down the path to becoming a Mainstream Programming Language™️. This sets up the question that I'm waiting to get answered: is Rust actually complex enough that it should be a niche PL rather than a mainstream PL?

How do current Rust devs feel about that so far?

perhaps he should have offered even one example where the borrow checker forced a "more complex" design. over time, I've come to realize the types of design decisions the borrow checker guides you to make are excellent for producing robust, reliable software.
I use Rust both professionally for parsing large datasets and image processing, and on most of my personal projects. I'm probably a little biased, since I both aesthetically like how Rust "feels" and that a lot of how it deals with the complexity of computers fits well with my own mental map of how computers work. Whether that's a chicken or the egg situation is up for debate...

That said, I think a counter argument here comes back to they complexity budget. I don't feel like language design and borrow checker are inherently more complex, but rather that they explicitly pull out that complexity, but in a way that feels manageable. I know that that since writing more Rust, my code written in other languages like C++ or even Python have started started having patterns that I picked up from my work in Rust, and that I qualitatively feel like that has raised my code quality in those languages. I'm also definitely more aware of some of the hidden complexity in certain tasks like dealing with system paths.

So at least in some degree of summary: no. I like the level of abstraction and complexity Rust has, and the mechanisms in place for dealing with that complexity have largely seemed both well thought-out and implemented such that they are accessible to a mainstream audience.

Thanks for the insight!
Personally, I find the argument too abstract. And many of the points are contrary to my actual experience. To give one concrete example,

> Rust’s way of managing memory is unique and clever. Unique and clever are generally seen as good things, but in software development they usually lead to difficulties with long-term maintenance, among other issues

The citations he gives are

1. a stack overflow post

2. a blog post (by an author I respect, but still)

I don't think that this alone proves his point. Even if we ignore that aspect of things, Rust is by far the easiest programming language I've ever had to do long-term maintenance on. This is specifically due to the guarantees.

So when I read the above, I see a very general argument, and my experience contradicts it here, so I don't really agree.

I am also, of course, incredibly biased.

We'll s/biased/credible/ on this one.

Can you think of any cases where he might be right? How often do you hit, for instance, "This code cleanly fit its original construction, but now I have to add some complexity for new cases, and Rust is making that harder?" Put another way, once you're familiar with the borrow checker, how often do you find yourself or your teams fighting it?

It just depends. It's really hard to talk about this stuff because it's always so variable. I think that Rust tends to expose complexity in places that other languages paper over. This means that it can feel like Rust is adding complexity, but it's not really. It's surfacing the underlying complexity. This makes the end result more robust. It takes some practice, and there is the perennial question of "how long does it take to get to that point, and how much effort is it?" I think this line of questioning is more likely to be a real reason to not choose Rust, and is one of the reasons we've been trying to lower the learning curve.

> Put another way, once you're familiar with the borrow checker, how often do you find yourself or your teams fighting it?

Extremely rarely, if ever. It yells at you, you go "oh yeah, oops" and fix it, and move on with life.

But, I should qualify that's mostly personal experience and what I hear from other folks generally and other teams at work; my team at work doesn't really write Rust, our main codebase is in Typescript and Go.

I just saw this thread by the ex-CTO of Chef, it matches my experiences here: https://twitter.com/adamhjk/status/1239989909714173952

Okay thanks for the insights. Learning curve may reduce the available engineers (at least for a bit) but my concern is about whether the PL's premises are holding up in real world usage, which it sounds like (for you and other commenters) it has.
I only have a passing familiarity with Rust. I've worked through some tutorials just to try it out, but its not even close to one of my daily drivers. Coming from that perspective, it is really hard to evaluate the argument this article makes because the author provides no concrete examples of this extra complexity. Does anyone have a clear example a non-expert can look at?
I think the premise is flawed ("Rust way is clever, ergo, problems").

BTW, I have many troubles with rust, that after more than a year are more stable (starting with rust I could have believed what this post say):

https://www.reddit.com/r/rust/comments/fj824y/whats_your_con...

I rewrite a huge (for a solo dev like me) codebase from .net/f# to rust, used in ERP-like app by the small/medium companies on my country. As "normal" and "boring crud" apps as you can tell.

The complexity of the development wet DOWN, A LOT. Even taking in consideration the use of F# (that I also pick to reduce the burden of using C#), the code have MUCH less bugs and troubles. We were on "fire mode" for some months and after the switch, all is calm as I have not experience in a lot of time.

And, as I say: I'm a solo developer. Still learning rust.

---

BTW: I only hit serious blocks working in a relational language on the side. For "normal" enterprise coding? Rust is a total win.

Quote 46 from here: https://www.junauza.com/2010/12/top-50-programming-quotes-of...

6. "A programming language is low level when its programs require attention to the irrelevant." - Alan J. Perlis.

Indeed, Rust is "a systems programming language".
What's irrelevant tho? Like memory layout might seem irrelevant on one hand, on the other if you care about perf you need to know this.
but perf is "irrelevant"
In times of climate change, is it? If you can run one machine instead of 60, that is not just a financial win, it is also a ecology win. Not to mention that having 60 machines suddenly requires additional complexity in other parts: Load balancers, memcaches, distributed somethings. Performance also buys simplicity.
My guess is that the comment you were responding to was sarcastic.
It's obviously dependent on the use case. This is probably the main reason for the abundance of programming languages.
The intentions are good. (Just like those of C++.) Problem is, as they say, it is the road to hell that is paved with them.
Ideally (not realistically), every application should be written in its own language. In any case, trying to be "everything to everyone" inevitably leads to "problems."
I would personally never reach for Rust for a project unless I needed bare-metal performance. I can make API calls + database calls + interact with USB devices/filesystems in node.js with much less complexity and a much stronger ecosystem.
I don't know why you're downvoted; this is a decent argument in my opinion. Node has a fantastic ecosystem, and API + database calls (aka, IO) are its bread and butter.

We see people switch from Rust to node due to scale and reliability. If you're not feeling those pains from Node, then you should absolutely keep using it!

> order to manage memory the way the borrow checker wants, the programmer is at best tempted, and at worst forced, to add complexity to the program

Dubious claim; in fact, the opposite seems true, since simpler code passes the borrow checker more easily

There is a fair point here that always gets brushed under the rug when discussing Rust vs X: Not having a GC means Rust forces you to think about memory allocation throughout your program's logic & structure. That's a cost and many programs don't benefit from it at all.

I had a Rust vs Haskell debate with a VPE at a company (he wanted to move to Rust.) He refused to acknowledge that the fact that Haskell has a GC is a big advantage over Rust for many applications (ours included.) It didn't help that he (somewhat arrogantly) fashioned himself a "systems engineer" and would've chosen C++ if he could've.

It wasn't the crux of the argument (there's a lot more to those languages) and this VPE clearly wanted to move away from Haskell from day 1, but nonetheless - a very frustrating discussion to have.

I'm not a Rust expert though so please correct me if there's a way to right large Rust programs without worrying about memory management.

You can consistently use reference counting if you want to avoid thinking too much about memory management.

Haskell vs Rust is probably a question of much more than a GC or not though.

Reference counting requires extra syntax, though.
> Haskell vs Rust is probably a question of much more than a GC or not though.

Oh yes 100%

My issue was that the discussion was disingenuous. GC was used to knock Haskell, but the cost of Rust's memory management model was not listed at all, thus painting an unbalanced pro/con picture (the scales were unbalanced!)

> I'm not a Rust expert though so please correct me if there's a way to right large Rust programs without worrying about memory management.

That's the thing: it depends on what you mean by "think." At this point, I never think about memory in Rust; that's what the borrow checker is for. I write my code, usually it's just fine, sometimes there's an error and I go "oops" and fix it.

Consider how you'd feel if someone said "ugh, you know, Haskell makes you think about types throughout your program's logic and structure. That's a cost many programs don't benefit from at all." I would assume, given that you like Haskell, you understand that types are a tool to help you write programs, and dealing with the compiler telling you about types isn't really a burden. Same with Rust. (lifetimes are types!)

I get what you're saying, but does every program benefit from tracking & managing lifetime of every object? It is clearly beneficial for plenty of programs (Rust is clearly best-in-class imo for non-GC programming) but is it for all?

And Haskell's types aren't necessarily what you want either (I still write bash and python and go for a reason!), but I'm guessing they're more generally applicable than lifetimes. I would love to be wrong & learn more though :)

In the same way that you still find bash and python and go useful, I would agree that not every program needs Rust.

> I'm guessing [types are] generally more applicable than lifetimes.

I think this is an open question! A lot of people argue (you can see some of it in this thread) that Rust's rules teach them a certain programming style that carries over into other languages.

If memory is the only resource you have to worry about, then garbage collection is (usually) fine. If you have to worry about file handles, sockets, semaphores, and the like, then GC solves 90% of the problem (memory), but usually leaves you worse off for dealing with the other resources.

Why does it usually leave you worse off? Because, since it's garbage collected, the language usually doesn't see the need to also provide a good way for the programmer to manage lifetimes, because, hey, we've got garbage collection, so why would they need to? The result is that the programmer has no help at all with the other resources.

So that's where I think the line is. Do you just have memory to worry about? Or do you have other resources as well?

And, to be clear: Yes, if you only have memory to worry about, garbage collection is fabulous. A whole set of problems just... goes away. It's very freeing.

Thank you - this clears stuff up. I see now how lifetimes provide a tool to solve a very important class of problems.

I know Haskell is trying to get Linear Types for those purposes (with a paper + working ghc branch) but even those are going to take time to get nice imo.

Would think the architecture & design of software applications are the natural place to manage complexity, whatever the programming language is. It is simple an illusion to rely on programming language alone to manage complexity.