My negative views on Rust (2023)

156 pointsposted 13 hours ago
by rc00

184 Comments

jkelleyrtp

11 hours ago

"There are only two kinds of languages: the ones people complain about and the ones nobody uses".

---

Glad to see fluffy negative articles about Rust shooting up the first slot of HN in 20 minutes. It means Rust has made finally made it mainstream :)

---

The points, addressed, I guess?

- Rust has panics, and this is bad: ...okay? Nobody is writing panic handling code, it's not a form of error handling

- Rust inserts Copy, Drop, Deref for you: it would be really annoying to write Rust if you had to call `.copy()` on every bool/int/char. A language like this exists, I'm sure, but this hasn't stopped Rust from taking off

- Fetishization of Efficient Memory Representation: ... I don't understand what the point is here. Some people care about avoiding heap allocations? They're a tool just like anything else

- Rewrite anything and it gets faster: okay sure, but there are limits to how fast I can make a Py/JS algorithm vs a compiled language, and Rust makes writing compiled code a bit easier. People probably aren't rewriting slow Python projects in C these days

- Rust is as complex as C++: ...no, it's not. Rust really hasn't changed much in the past 6 years. A few limitations being lifted, but nothing majorly new.

- Rust isn't as nice of community as people think: subjective maybe? People are nice to me at conferences and in discussion rooms. There's occasional drama here and there but overall it's been pretty quiet for the past year.

- Async is problematic: Async Rust really is fine. There's a huge meme about how bad it is, but really, it's fine. As a framework author, it's great, actually. I can wrap futures in a custom Poll. I can drive executors from a window event loop. Tokio's default choice of making `spawn` take Send/Sync futures is an odd one - occasionally cryptic compile errors - but you don't need to use that default.

I'm unsure why this article is so upvoted given how vapid the content is, but it does have a snappy title, I guess.

hyperbrainer

11 hours ago

> Rust is as complex as C++: ...no, it's not.

Maybe not yet, but it is heading in that direction; and I only say this because of the absolutely giant pile of features in unstable that seem to be stuck there, but I hope will eventually make its way to stable at some point.

> Async Rust really is fine

I dunno. Always thought it was too complicated, but as another person pointed out avoiding Tokyo::spawn solves many issues (you said this too, I think). So maybe, not Rust's fault :D

Diggsey

8 hours ago

> Maybe not yet, but it is heading in that direction;

It's definitely getting more complex, but C++ has a huge lead haha. C++ is like a fractal in that you can look at almost any feature closer and closer to reveal more and more complexity, and there are a lot of features... Here's a page on just one dark corner of the language: https://isocpp.org/wiki/faq/pointers-to-members and it interacts in interesting ways with all the other corners (like virtual vs non-virtual inheritance) in fun and exciting ways...

Also, there are far more ways to cause UB in C++. Rust has a big lead on formalizing what constitutes UB, and even those rules you only need to learn if you are using "unsafe", whilst in C++ you don't have that luxury.

tialaramex

an hour ago

> Also, there are far more ways to cause UB in C++.

As well as lots of Undefined Behaviour, C++ also has what its own experts call "False positives for the question is this a C++ program" the Ill-Formed No Diagnostic Required features, nothing like these exist in Rust, they're cases where you can write what appears to be C++ but actually although there are is no error or warning from the compiler your entire program has no meaning and might do absolutely anything from the outset. I've seen guesses that most or even all non-trivial C++ invokes IFNDR. So that's categorically worse than Undefined Behaviour.

Finally, C++ has cases where the standard just chooses not to explain how something works because doing so would mean actually deciding and that's controversial so in fact all C++ where this matters also has no defined meaning and no way for you to discover what happens except to read the machine code emitted by your compiler, which entirely misses the point of a high level programming language.

One of the things happening in Rust's stabilization process is solving those tough issues, for example Aria's "Strict Provenance experiment" is likely being stabilized, formally granting Rust a pointer provenance model, something C++ does not have and C23 had to fork into a separate technical document to study.

googh

30 minutes ago

Most (if not all) of your posts here on HN boil down to "C/C++ bad, Rust good". I wonder what you are trying to achieve by this, but I assure you that this does not do Rust any favor other than giving the impression that the Rust community is obnoxious.

CryZe

11 hours ago

> Maybe not yet, but it is heading in that direction

About 95% of the unstable features lift limitations that most people expect not to be there in the first place. I'm not aware of all too many that aren't like that.

faitswulff

7 hours ago

> Maybe not yet, but it is heading in that direction

When people say that Rust is complex, they often neglect to differentiate between implementation complexity and developer facing complexity. The implementation complexity is growing in part to support the end user simplicity. I also don't understand why anyone feels the need to know every feature of the language. You can just learn about and use the features that you need.

s17n

11 hours ago

> Fetishization of Efficient Memory Representation: ... I don't understand what the point is here. Some people care about avoiding heap allocations? They're a tool just like anything else

The point is that dealing with the Rust borrow checker is a huge pain in the ass and for most Rust applications you would have been better off just using a garbage collected language.

CryZe

11 hours ago

> huge pain in the ass

Maybe if you structure your code weirdly? I haven't encountered a major borrow checker issue that I couldn't easily resolve in many years.

delifue

2 hours ago

It's not appropriate to say that "having trouble with borrow checker means code is wrong". Sometimes you just want to add a new feature and the borrow check force you to do a big refactor.

See also: https://loglog.games/blog/leaving-rust-gamedev/

tinrab

5 minutes ago

I hear this constantly but never see any examples of what they actually mean, or it's coming from misunderstandings of what the language is. I've seen people say how well the async code could be if Rust got a garbage collector. For the borrow checker specifically, I think it's important to understand smart pointers, Cell/RefCells, other primitives, and the fact that you don't have to solve everything with references.

iknowstuff

11 hours ago

I haven’t had to „deal with” the borrow checker since like 2018. It’s quite smart

jkelleyrtp

11 hours ago

I mean, maybe?

If you come into Rust thinking you're going to write doubly-linked lists all day and want to structure everything like that, you're going to have a bad time.

But then in python you run into stuff like:

```

def func(list = []):

   list.append(1)
```

and list is actually a singleton. You want to pull your hair out since this is practically impossible to hunt down in a big codebase.

Rust is just different, and instead of writing double-pointer code, you just use flat structures, `Copy` keys, and `loop {}` and move on with your life.

Izkata

10 hours ago

FYI this site doesn't use ``` for code blocks, it uses indentation (two spaces).

https://news.ycombinator.com/formatdoc

mewpmewp2

6 hours ago

A bit off topic, but how do people usually write code here or on Reddit, I always find it to be really cumbersome to make sure there's two spaces etc in front of everything? Is there some formatting tool that I'm not aware of that everyone else uses?

Because in both forums I keep coming back to edits, and it takes forever to edit some of the things, manually. I feel like I'm being stupid or the UX of all of that is just so terrible.

satvikpendem

6 hours ago

I actually use a formatting tool online if on mobile, or just vim if on the computer, which can add two spaces in front of every line.

Izkata

5 hours ago

> or just vim if on the computer

I use Firefox + Tridactyl + the native extension, so with the cursor in any text field I can hit Ctrl+i and it pops up a gvim window with the contents of that text field. When you save+quit, it copies the contents back into the field.

So glad someone figured out how to do this again once Vimperator died.

steveklabnik

5 hours ago

I write it in play.rust-lang.org, then indent using the vim keybindings. I do this even for not rust code.

fiedzia

11 hours ago

> this is practically impossible to hunt down in a big codebase

use linters, they keep getting smarter

s17n

6 hours ago

I have literally never used a doubly-linked list in my life, and I'm pretty sure that most programmers can say the same thing.

As for the example... yeah, Python is pretty terrible (for writing production codebases, I think its a great language for short-lived, one-person projects). Interesting that you mention Python because if you're considering Python and Rust for the same use case that's pretty bonkers, for anything that you might possibly have used Python to do there are many more natural choices than Rust. If you wouldn't have done it in C/C++ ten years ago, you probably shouldn't be doing it in Rust today.

johnnyanmac

8 hours ago

Yeah. I wouldn't use Rust as a scripting language for that reason. But some critical applications want that enforced correctness and (hopefully) proper performance to be guaranteed if you pass the compiler.

I want to eventually join the "50 engines for every game" race that is rust gsme engineer development, but I'm sure not going to have the fast iteration part of design be done in Rust. The renderer and all the managers should be absolutely solid, but some parts of games need you to break stuff quickly.

XorNot

8 hours ago

Having just delved into Rust a little (and then given up and decided to learn Dart/Flutter for more practical applications development - I don't need another language to make command line tools in), this one I did feel while I was going through documentation.

The problem is most of the important problems you deal with while programming require heap allocations: i.e. a lot of Rust advice is liable to lead you astray trying to find over-complicated solutions to optimizations you probably don't need up front.

So in terms of systems programming, Rust is technically good here - these are all things you'd like to do on low level code. On the other hand if you're making a bunch of web requests and manipulating some big infrequently used data in memory...Box'ing everything with Arc is probably exactly what you should do, but everyone will tell you to try not to do it (and the issue is, if you're like me, you're coding in the "figure out what and how to do it" phase not the "I have a design I will implement optimally" phase).

mondobe

8 hours ago

> Rust really hasn't changed much in the past 6 years.

Even more importantly than this, Rust has a major emphasis on backwards compatibility. The author mentions a "hamster wheel" of endless libraries, but, in Rust, nothing's forcing you to switch to a newer library, even if an old one is no longer maintained.

In general, the complexity of your project is completely up to you, and (at least to me) it seems like a lot of the new features (e.g. generator syntax) are trending towards simplicity rather than complexity.

csomar

2 hours ago

I was going to write a rebuttal but then I read your comment and it mirrored roughly what I was going to write.

> - Rust inserts Copy, Drop, Deref for you: it would be really annoying to write Rust if you had to call `.copy()` on every bool/int/char. A language like this exists, I'm sure, but this hasn't stopped Rust from taking off

One improvement here could be the IDE. I don't want to write `let s: String` every time but the IDE (neovim LSP) does show it. It'd be good if I can get the full signature too.

> Async is problematic

Async Rust is by far the best Async out there. Now when I use other languages I am essentially wondering what the hell is going on there. Is there an executor? Is there a separate thread for this? How/When is this getting executed? Async Rust doesn't execute anything and as a result you can get an idea of how the flow of your program goes (as well as pick an executor of your choice, might not seem important if you are on the Tokio bandwagon but if you are in an envrionment where you need a custom executor and you need to control CPU threads, Rust Async suddenly makes a lot of sense)

ggregoire

9 hours ago

> I'm unsure why this article is so upvoted given how vapid the content is, but it does have a snappy title, I guess.

rust, sqlite, htmx... there is a small list of techs that always get massively upvoted on hn, whatever the content or quality of the article.

marcosdumay

9 hours ago

Well, if the entirely of that list is as awesome as those 3, then it's a good list to be.

johnnyanmac

8 hours ago

>it would be really annoying to write Rust if you had to call `.copy()` on every bool/int/char. A language like this exists, I'm sure, but this hasn't stopped Rust from taking off

Well C++ does the same by default. You need to opt in for deep copies. C++ doesn't drop by default but modern practices like Smart pointers do.

>I'm unsure why this article is so upvoted given how vapid the content is, but it does have a snappy title, I guess.

Even HN isn't immune to the 90-9-1 rule.

throwawaymaths

10 hours ago

I've seen a case where the rust panic handler is used in FFI and this creates a memory leak.

pclmulqdq

8 hours ago

> Rust has panics, and this is bad: ...okay? Nobody is writing panic handling code, it's not a form of error handling

As far as I know, the issue with the panics is that things panic a lot. Times when C or C++ will limp along in a degraded state and log something for you to look at will cause your Rust program to crash. That turns things that are not problems into things that are problems.

morning-coffee

7 hours ago

First, things don't panic a lot in my experience writing Rust for the past three years. Second, when things do panic, it indicates a defect in the code that needs to be fixed. Aborting the program with a stack dump is the perfect behavior for seeing the state and the invariant that was violated and then figuring out the fix. Contrast this to C or C++ "limping along", usually until a later invariant causes a crash and being further away from and obscuring the true root cause, and we see why C and C++ code is generally still so bug-ridden relatively speaking. Fail-fast is not just a buzz word and program bugs are not recoverable errors. See https://joeduffyblog.com/2016/02/07/the-error-model/

pclmulqdq

7 hours ago

These arguments get said a lot and they are all fine in theory, but in practice, all code over a certain size has a tremendous number of latent bugs, even Rust code. At a certain scale, you are virtually guaranteed to be running in a degraded mode of some kind. If the consequences of those latent bugs are operational nightmares, that's a problem. Most people would rather be able to roll in at 10 am to debug a minor issue from logs and traces than get a page at 1 am with 1000 stack traces in it.

morning-coffee

6 hours ago

If your goal is to converge on correctly functioning software, you know, for the benefit of the users of it, then fail-fast can help. If your goal is to optimize the sleep patterns of devops people and make changes to code without testing before releasing it to production, yeah... do what you need to do. :)

pclmulqdq

6 hours ago

You can have correctly-functioning software when parts of it are operating in a weird way. The complaint I have heard about Rust crashes is that the default behavior is to crash in any situation that could possibly be weird.

By the way, the trade you're talking about is great for desktop software (especially for browsers), but server-side software at scale is a bit different.

The borrow checker and all the Rust safety stuff is also completely orthogonal to most forms of testing. You don't get to do any less because your language protects you against a specific class of memory-related errors.

beeflet

9 hours ago

>Rust inserts Copy, Drop, Deref for you: it would be really annoying to write Rust if you had to call `.copy()` on every bool/int/char. A language like this exists, I'm sure, but this hasn't stopped Rust from taking off

Is it possible to disable this behavior? I think it might be useful as a learning tool to familiarize myself with the Traits.

lovethevoid

11 hours ago

This was an oddly defensive and vapid comment. Mostly just handwaving away any views the article brings up, of which at least the article expands on their thoughts. This comment is just "meh not a bad thing" repeatedly. Why is this comment being upvoted?

jkelleyrtp

10 hours ago

The title is inflammatory and yet there are few nuanced takes in the article. It's weird to see it shoot to the top of HN.

I think the loglog article is a much better, nuanced, full critique of Rust.

https://loglog.games/blog/leaving-rust-gamedev/

The internet is just so full of negativity these days. People upvote titles but don't read articles. Reading about people's views on subjects is useful, but I don't think this one is.

Shatnerz

9 hours ago

Inflammatory? "My Negative Views on X" is pretty far from inflammatory. It is exactly what the post was, with some positivity sprinkled in as well.

pessimizer

10 hours ago

> This was an oddly defensive and vapid comment.

Even comparatively, next to your own comment? I have no specific idea of what you object to or why, but I have learned that you are upset.

Ygg2

11 hours ago

> Rust isn't as nice of community as people think

It's a numbers game. As the number of people using Rust grows, so does the number of Jerks using Rust. And it's not like the Rust community is a stranger to bullying maintainers of crates for various things.

> Async is problematic: Async Rust really is fine.

It's... OK. It has a few issues, that hopefully will get fixed, like making Pin from a generic struct into a type of reference. e.g. instead of `Pin<&str>` you would write `&pin str`.

There is also the coloring problem which is quite a hassle and people are looking into possible solutions.

api

10 hours ago

IMHO the biggest Rust async annoyance is exactly this:

> Tokio's default choice of making `spawn` take Send/Sync futures

... combined with lack of structured concurrency.

This means async tasks look like threads in every respect, causing you to end up using Arc<> and other concurrency constructs all over the place where they ought not be necessary. This harms efficiency and adds verbosity.

khuey

8 hours ago

It's not too hard to do tokio without Send/Sync futures. See the example in https://docs.rs/tokio/latest/tokio/task/struct.LocalSet.html... It's kind of annoying that the current_thread flavor of the executor doesn't automatically enter a LocalSet and make spawn_local work out of the box but it's easy enough to do at the beginning of your program.

Animats

11 hours ago

My big problem with Rust is too much "unsafe" code. Every time I've had to debug a hard problem, it's been in unsafe code in someone else's crate. Or in something that was C underneath. I'm about 50,000 lines of Rust into a metaverse client, and my own code has zero "unsafe". I'm not even calling "mem", or transmuting anything. Yet this has both networking and graphics, and goes fast. I just do not see why people seem to use "unsafe" so much.

Rust does need a better way to do backlinks. You can do it with Rc, RefCell, and Weak, but it involves run-time borrow checks that should never fail. Those should be checked at compile time. Detecting a double borrow is the same problem as detecting a double lock of a mutex by one thread, which is being worked on.

Const-me

11 hours ago

> I just do not see why people seem to use "unsafe" so much

Because it’s impossible to implement any non-trivial data structures in safe Rust. Even Vec has unsafe code in the implementation to allocate heap memory. When you need efficient trees or graphs (I doubt any non-trivial software doesn’t need at least one of them), unsafe code is the only reasonable choice.

C++ does pretty much the same under the hood, but that’s OK because the entire language is unsafe.

C# has an unsafe subset of the language with more features, just like Rust. However, it runs inside a memory-safe garbage collected runtime. Even List and Dictionary data structures from the standard library are implemented with safe subset of the language. Efficient trees and graphs are also trivial to implement in safe C#, thanks to the GC.

pcwalton

10 hours ago

> When you need efficient trees or graphs (I doubt any non-trivial software doesn’t need at least one of them), unsafe code is the only reasonable choice.

To name one example, the AnimationGraph in Bevy is implemented with petgraph, which is built using adjacency lists, and doesn't use any unsafe code in any of the parts that we use. It is very high-performance, as animation evaluation has to be.

Const-me

9 hours ago

> It is very high-performance, as animation evaluation has to be

Are you sure evaluating these animations is performance critical? I doubt games have enough data to saturate a CPU core doing that. Screens only have 2-8 megapixels; animated objects need to be much larger than 1 pixel.

If you animate bones for skeletal animation that’s still not much data to compute because real life people have less than 256 bones. You don’t need much more than that even if your models have fancy manually-animated clothes.

refulgentis

7 hours ago

> Are you sure evaluating these animations is performance critical?

Isn't this obviously true? A key part of UI work is avoiding "jank", which commonly refers to skipped frames.

> I doubt games have enough data to saturate a CPU core doing that.

Got a bit lost here: games?

> Screens only have 2-8 megapixels.

4 bytes per pixel, 32 MB/frame. 120 frames / sec = 8 ms/frame. 3.84 GB/second.

> animated objects need to be much larger than 1 pixel.

Got lost again here.

In general, I'm lost.

First, there's a weak claim that all performant data structures in Rust must use unsafe code.

I don't think the author meant all performant data structures must use unsafe code.

I assume they meant "a Rust data structure with unsafe code will outperform an equivalent Rust data structure with only safe code"

Then, someone mentions a 3D renderer, written in Rust, is using a data structure with only safe code.

I don't understand how questioning if its truly performant, then arguing rendering 3D isn't that hard, is relevant.

jltsiren

10 hours ago

Non-trivial data structures are often just a bunch of arrays/maps with additional semantics. You may consider implementing/using unchecked versions of basic operations for a little bit of additional performance. If you implement (de)serialization yourself, you may need unsafe code. Sometimes the safety of deserialization may be a convenient lie, if checking the invariants fully would be too expensive. And sometimes you may want to expose internal helper functions for various purposes, which may have to be marked unsafe if they can break the invariants.

Beyond that, you only need unsafe code for specific kinds of data structures. At least in my experience.

Const-me

9 hours ago

> Non-trivial data structures are often just a bunch of arrays/maps with additional semantics

This might be fine for code which consumes data structures implemented by other people. The approach is not good when you actually need to implement data structures in your program.

In modern world this is especially bad for a low-level language (marketed as high performance, BTW) because the gap between memory latency and compute performance is now huge. You do need efficient data structures, which often implies developing custom ones for specific use cases. This is required to saturate CPU cores as opposed to stalling on RAM latency while chasing pointers, or on cache coherency protocol while incrementing/decrementing reference counters from multiple CPU cores.

Interestingly, neither C++ nor C# has that boundary, for different reasons: C++ is completely unsafe, and safe C# supports almost all data structures (except really weird ones like XOR linked lists) because GC.

jltsiren

9 hours ago

I used to think like that. Then C++11 arrived, and I realized I could get effectively the same performance with containers and move semantics, while spending less effort on writing and debugging the code.

If you need an array for your custom data structure, a standard library vector is almost always good enough. Associative arrays are a bit more tricky, but you should be able to find a handful of map implementations that cover most of your needs. And when you need a custom one, you can often implement it on top of the standard library vector.

ryandrake

7 hours ago

The C++ Standard Library containers are very good and generic, and almost always the right tool to reach for. People are finally giving up on that notion that their own custom linked list is so much better than <list>. My estimate is that out of all the C++ programmers, 1% of them think that the C++ standard containers are not appropriate for their application, and only 1% of that 1% is right, due to their extremely specialized application needs.

bubaumba

10 hours ago

>> I just do not see why people seem to use "unsafe" so much

>Because it’s impossible to implement any non-trivial data structures in safe Rust. Even Vec has unsafe code

Hmm.. wasn't memory safety the main selling point for rust? If not the only. Now mix of two languages looks even worst than one complex. Especially taking into account that it can be paired with safe language from long list. Don't know what rust fans are thinking, but from outside it doesn't look very attractive. Definitely not enough to make a switch. Julia looked better at first, but turned out to be just a graveyard of abandoned academic projects.

pcwalton

9 hours ago

> Now mix of two languages looks even worst than one complex.

The point is that the vast majority of code doesn't have to be unsafe. Empirically, Rust code has far fewer memory safety problems than non-memory-safe languages.

TheRoque

9 hours ago

Memory safety without gc is not the only reason people use rust. It's also nicer to use than C++ for multiple reasons (language features, included package manager, easy to integrate tests...)

eddd-ddde

10 hours ago

You fan wrap unsafe implementations with safe APIs. The point is there's an explicit boundary between unsafe an safe.

okanat

9 hours ago

Nope it isn't. You just aren't experienced in system programming. Working with hardware is unsafe since it has state that one cannot completely encapsulate in a single program. The entire specific design of a chip isn't available to programmer; only the machine code is. We usually don't know how a processor decides to cache things or switch to kernel permission level. Usually this isn't even the level we're at, OSes have private internals that change behind the programs and they are not accessible from user space. Pressing Ctrl+C to interrupt changes so many things in memory, it would be outright impossible to write programs that handle every single thing.

The fundamental / syntactic promise of Rust is providing mechanisms to handle and encapsulate unsafety such that it is possible to construct a set of libraries that handle the unsafety in designated places. Therefore the rest of the program can be mathematically proven to be safe. Only the unsafe parts can be unsafe.

Coming from Java or Go or Js or Python angle wouldn't be the same. Those languages don't come with mechanisms to let you to make system calls directly or handle the precise memory structure of the data which is necessary when one is communicating with hardware or the OS or just wants to have an acceptable amount of performance.

In C++, the compiler can literally remove your code if you sum or multiply integers wrong or assume the char is signed/unsigned. There is no designated syntax that limits the places possible memory overflow error happen. The design of the language is such that some most trivial oversight can break your program silently and significantly. It is too broad so it is not possible to create a safe and mathematically proven and performant subset with the C and C++ syntax. It is possible with Rust. It is like the difference of chips that didn't have a hardware mechanism to switch between user and kernel mode so everything was simply "all programs should behave well and no writes to other programs' memory pinky promise".

Rust doesn't leave this just as a possibility. Its standard library is mostly safe and one can already write completely safe and useful utilities with the standard library. The purpose of the standard library is provide you ways to avoid unsafe as much as possible.

Of course more hardware access or extremely efficient implementations would require unsafe. However again, only the unsafe parts can cause safety bugs. They are much easier to find and debug compared to C++. People write libraries for encapsulating unsafe so there are even less places that use unsafe. If people are out of their C++ habit, reaching for the big unsafe stick way too often, then they are using Rust wrong.

Whatever you do, there will be always a need for people and software that enables a certain hardware mode, multiply matrices fast, allocates a part of display for rendering a window etc. We can encapsulate the critical parts of those operations with unsafe and the rest of the business logic can be safe.

beeflet

8 hours ago

> In C++, the compiler can literally remove your code if you sum or multiply integers wrong or assume the char is signed/unsigned. There is no designated syntax that limits the places possible memory overflow error happen. The design of the language is such that some most trivial oversight can break your program silently and significantly.

Here is an interesting case of an optimization-triggered bug in Rust code I've heard of: https://www.youtube.com/watch?v=hBjQ3HqCfxs

pcwalton

9 hours ago

> I'm about 50,000 lines of Rust into a metaverse client, and my own code has zero "unsafe". I'm not even calling "mem", or transmuting anything. Yet this has both networking and graphics, and goes fast. I just do not see why people seem to use "unsafe" so much.

I agree. I rarely ever use unsafe, and only as a last resort. Unsafe code is really not needed to achieve high performance.

> Rust does need a better way to do backlinks. You can do it with Rc, RefCell, and Weak, but it involves run-time borrow checks that should never fail.

I think this will basically turn into provably-correct data structures. Which is possible to do, and I've long thought there should be systems built on top of Rust to allow for proving these correct. But we should be clear that something like Idris is what we're signing up for. Whatever it is, it is assuredly going to be far more complex than the borrow check. We should basically only use such systems for the implementations of core data structures.

Animats

3 hours ago

> I think this will basically turn into provably-correct data structures.

That's kind of what I'm thinking. The basic idea is to prove that .upgrade().unwrap() and .borrow() never panic. This isn't all that much harder than what the borrow checker does. If you have the rule that the return value from those functions must stay within the scope where they are created, then what has to be proven is that no two such scopes for the same RefCell overlap. Sometimes this will be easy; sometimes it will be hard. A reasonable first cut would be to check that no such scopes overlap for a specific type, anywhere. That's rather conservative. If you can prove that, you don't need the checking. So it's an optimization.

pshc

11 hours ago

> Rust does need a better way to do backlinks. You can do it with Rc, RefCell, and Weak, but it involves run-time borrow checks that should never fail. Those should be checked at compile time.

It's not clear to me how rustc could detect a dangling backlink in a tree structure at compile time. Seems impossible short of adding proofs to the type system.

o11c

8 hours ago

If the language actually supported a full set of memory policies it would be quite possible.

Unfortunately it only thinks about are unique, an opinionated form of borrowed ownership, and a little bit about shared (weak I think is punted entirely to the library?), and not all other ownership policies can effectively be implemented on top of them.

The usual thing approach would be:

  given two types, P and C (which may be the same type in case of homogeneous trees, but this), with at least the following fields:

  class P:
    child1: ChildPointer[C]
  class C:
    parent: ParentPointer[P]
Then `p.child1 = c` will transparently be transformed into something like:

  p.child1?.parent = null
  c?.parent?.child1 = null # only needed if splice-to-steal is permitted; may need iteration if multiple children
  p.child1 = c
  p.child1?.parent = p
Note that ChildPointer might be come in unique-like or shared-like implementations. ParentPointer[T] is basically Optional[UnopinionatedlyBorrowed[T]].

A have a list of several other ownership policies that people actually want: https://gist.github.com/o11c/dee52f11428b3d70914c4ed5652d43f...

hyperbrainer

11 hours ago

> I just do not see why people seem to use "unsafe" so much.

SIMD seems to be a big one.

Ygg2

11 hours ago

> My big problem with Rust is too much "unsafe" code.

I hear cargo-geiger is useful identifying such crates.

> I just do not see why people seem to use "unsafe" so much.

Because it's:

A) fast (branchless access)

B) fast (calling C libs or assembly)

C) fast (SIMD)

D) people think unsafe Rust is easier

Want to write a JSON parser that will gobble up gigabytes per second? Your only way is removing as many branches and use assembly as much as possible. Doubly so on stable! I guess the same goes for making a "blazingly fast"™ graphical stack.

People that think unsafe is easier, shouldn't be writing unsafe code. Writing unsafe code correctly is like juggling burning chainsaws. Saying that's easier than using chainsaws is moronic at best.

EDIT: Consider following, if each of your unsafe {} blocks doesn't contain a

    // SAFETY:
    // Detailed explanation of invariants 
One of the chainsaws just cut off your leg.

johnnyanmac

8 hours ago

>people think unsafe Rust is easier

If that's their line of thought, I don't know why they simply don't use C/++. Or even C# with unsafe blocks. I know you said the same, but I wanted to reiterate that.

But yes, I can see a few very specific cases where unsafe access is needed. Emphasis on "few". I think anything past some fundamentals should be at best a late optimizing step after an MVP is established.

I also think, if it's not already there, that crates should be able to identify if it's "safe" or "unsafe". Same mentality where I'd probably want to rely on safe crates until I need to optimize a sector and then look into blazing fast but unsafe crates.

ritcgab

11 hours ago

It's ugly but it's inevitable in some sense. The author should know what they are doing, and `// SAFETY:` comment is a must.

fiedzia

11 hours ago

No. Nobody is going read those (because most people won't even know that some unsafe is buried 5 layers of dependencies below what they work with). The author should make reasonable effort to prove the code is working correctly (and cannot be abused) by other means if possible. It might be a domain issue, so far all my apps are 100% safe (not counting libraries).

nneonneo

7 hours ago

You put those safety comments in two places: when you declare an API as being unsafe, and when you use an unsafe API. Not coincidentally, those are the two places in the language that force you to use the “unsafe” keyword. If you declare a safe API that uses unsafe under the hood, it’s on you to ensure that it’s safe to call under any situation, so that callers can call it without worrying that their program is suddenly unsafe. If you can’t guarantee that your API is safe under all circumstances, you need to declare it unsafe and make it the caller’s job to use it safely.

n_plus_1_acc

10 hours ago

Unsoundness is considered a bug and should be reported and fixed.

alfiedotwtf

7 hours ago

I’ve been using Rust almost daily since 2015 and I’ve used unsafe twice - both when interoping with C.

I don’t know what fancy things you’re doing with unsafe that you’re seeing it on a daily basis… maybe it’s a you problem

Yujf

an hour ago

It is explicitly mentioned that ubsafe is in their dependencies not their own code.

sebastos

8 hours ago

"X is as complex as C++" is a preposterous statement for all values of X.

A lot of people seem to assume that "C++ is complex" is referring to how the committee adds new language features every 3 years. The conventional wisdom that C++ is wickedly difficult to learn is NOT about "oh man, now I need to learn about the spaceship operator?" C++ is an almost unfathomably bottomless pit. From the arcane template metaprogramming system to the sprawling byzantine rules that govern what members a compiler auto-generates for you, and on to the insane mapping between "what this keyword was originally introduced for" and "what it actually means here in _this_ context, there is no end to it. Keeping up with new language syntax features is an absolute drop in the bucket compared to the inherent complexity required to understand a C++11 codebase, build it (with a completely separate tool that you must choose) and manage its dependencies (with a yet different completely separate tool that you must choose).

You don't have to know anything about Rust to know that saying "Rust has become complex as C++" is objectively incorrect.

christianqchung

7 hours ago

Yeah, but in 12 years when reflection is in the language and is widely used, people will probably have to deal with a significantly increased amount of weirdness as a result of that feature. Though all that's to say the complexity gap between rust and C++ is only going to go up.

hyperbrainer

12 hours ago

Needs (2023)

> I predict that tracing garbage collectors will become popular in Rust eventually.

The use of Rc is already very widespread in projects when people don't want to deal with the borrow checker and only want to use the ML-like features of Rust (Sum types, Option, Error etc.)

> Rust has arrived at the complexity of Haskell and C++, each year requiring more knowledge to keep up with the latest and greatest.

I wonder when we will see the rise of Haskell like LanguageExtensions in Rust. AFAIK, pretty much everybody uses things like GADT, PolyKinds, OverloadedStrings etc. The most similar thing I can think of Rust right now for is python-like decorator application of things like builder macros using Bon.

> Async is highly problematic

Agreed. Tokyo is the only reason, I think, anybody is able to use Rust for this stuff.

tptacek

11 hours ago

Does Rc really resolve the core problem this post is talking about, which is that it's really painful to naturally express tree and graph structures in Rust? It feels like I mostly see people talking about building application-layer pointer systems with integers, which would be surprising if (in a single thread, perhaps) you could just Rc your way around the problem.

umanwizard

11 hours ago

> Does Rc really resolve the core problem this post is talking about, which is that it's really painful to naturally express tree and graph structures in Rust

No, it doesn't. If you naively express graphs containing cycles with `Rc` you will leak memory, just like you would with `std::shared_ptr` in C++.

ordu

11 hours ago

> Does Rc really resolve the core problem this post is talking about, which is that it's really painful to naturally express tree and graph structures in Rust?

No, but Gc will not resolve the core problem either. The core problem is that rust forbids two mutable pointers into one chunk of memory. If your tree needs backlinks from child nodes to parents, then you are out of luck.

tptacek

9 hours ago

In what way am I "out of luck"? It's trivial to express a tree, including one with backlinks, in Java.

jcranmer

7 hours ago

Rust's mutability rules specifically screw you over here (you can't have two mutable references to the same object, ever); most languages (including Java) don't have those rules.

I sometimes wish I could have a mode of Rust where I had to satisfy the lifetime rules but not the at-most-one-mutable-reference-to-an-object rule.

ordu

7 hours ago

Java doesn't enforce the rule "mutable XOR shared". But if you have a link "child" in the parent node, and a link "parent" in the child node, then parent.child.parent == parent, and compiler cannot know it.

So Rust as the language makes it impossible to do with &-pointers, while standard library of Rust allows it to do with combination of Option, Rc, RefCell but it is really ugly (people above says it is impossible, but I believe it is just ugly in all ways). Like this:

type NodeRef = Rc<RefCell<NodeInner>>;

struct Node { parent: Option<NodeRef>, left: Option<NodeRef>, right: Option<NodeRef> }

So the real type of `parent` field is Option<Rc<RefCell<NodeInner>>>. I hate it when it comes to that. But the ugliness is not the only issue. Now any attempt to access parent or child node will go through 2 runtime checks: Option need to check that there is Some reference or just None, and RefCell needs to check that the invariant mut^shared will not be broken. And all this checks must be handled, so your code will probably have a lot of unwraps or ? which worsens the ugliness problem.

And yeah, with Rc you need to watch for memory leaks. You need to break all cycles before you allow destructors to run.

If I need to write a tree in rust, I'll use raw-pointers and unsafe, and let allergic to unsafe rustaceans say what they like, I just don't care.

okanat

9 hours ago

and then your gc will leak it. Rust programs are not only safe but CPU and memory efficient.

truetraveller

8 hours ago

I simple standard mark-and-sweep GC will not "leak it".

hyperbrainer

11 hours ago

Considering that there exists a book about building linked lists in Rust[0], I am going to go ahead and say "Unclear" That does not matter though. It is easier (though verbose and often unidiomatic), and hence Rc has become really popular, especially with beginners.

[0] https://rust-unofficial.github.io/too-many-lists/

pcwalton

9 hours ago

Rc does solve the problem, but it often introduces interior mutability, which ends up causing usability problems. That's why at the end of the day adjacency representations (i.e. integers) are often preferred.

cmrdporcupine

11 hours ago

Sure, Rc/Arc absolutely solves this problem. It's not super idiomatic to go crazy with using it like that, but it's possible/acceptable.

Using SlotMap and integer ids, etc. doesn't I think offer any advantage.

tptacek

11 hours ago

I feel pretty comfortable with Rc and Arc, read the "too many lists" book, &c. and feel like it is not actually simple to model trees with Rc? What am I missing? I'd love to be convinced I'm wrong about this (I want to like Rust more than I do).

cmrdporcupine

10 hours ago

A tree of Rc/Arc<T> is a tree of references, and is really no different than a Java or Python reference value, except that you'll have to do explicit .clone()s

Is it mutability that's tripping you up? Because that's the only gotcha I can think of. Yes, you won't get mutability of the content of those references unless you stick a RefCell or a Mutex inside them.

tptacek

9 hours ago

Yes! Mutability is what's tripping me up! That is not a minor detail!

cmrdporcupine

7 hours ago

You can get something like what you're used to a "traditional" language without compiler safeguards by using RefCell and .borrow_mut() on it. That will let you get past the compile-time borrow checks but will do runtime borrow checking and throw panic if more than one borrow happens at runtime.

It's verbose, but it's explicit, at least.

So:

  struct Node {
    parent: Rc<RefCell<Node>>,
    left: Option<Rc<RefCell<Node>>>,
    right Option<Rc<RefCell<Node>>>,
  }
and just off the top of my head it'd be something like

  {
    let my_parent = my_node.parent.borrow_mut();
    ... do stuff with my_parent ...
  }
  ... my_parent drops out of scope here, now others can borrow ...
etc.

Haven't tried this in compiler my memory might not be right here.

tptacek

6 hours ago

I do know that it's possible, but when people complain about this --- as with this tweet, from a PL theorist:

https://x.com/LParreaux/status/1839706950688555086

... this is what they're talking about.

(I know the tweet is about the "idiomatic" answer to this problem, which is to replace references with indices into flat data structures).

nine_k

11 hours ago

Doesn't SlotMap save RAM and pointer dereferences?

cmrdporcupine

10 hours ago

What is a slotmap lookup... if not a pointer dereference, or at least a dereference out of a vector likely on heap... so probably a pointer...?

nicce

11 hours ago

> Agreed. Tokyo is the only reason, I think, anybody is able to use Rust for this stuff.

A lot of problems related to Tokyo can be avoided if you think your code as structured concurrency and avoid using Tokio::spawn. However, too often this is not possible.

written-beyond

10 hours ago

I haven't, yet, run into building rust apps that require highly complex async implementations with lifetimes etc. however excluding those situations I've found it very straightforward and easy to use. I've built some applications with a lot of moving parts, mpsc has always been a life saver.

hyperbrainer

11 hours ago

I don't have too much experience with async, but I have noticed a similar pattern. Maybe you are right.

bsder

10 hours ago

> The use of Rc is already very widespread in projects when people don't want to deal with the borrow checker and only want to use the ML-like features of Rust (Sum types, Option, Error etc.)

And the fact that this hasn't caused alarm is kind of an issue.

The problem with that is Reference Counting is WAY slower than good Garbage Collectors on modern CPUs. Reference Counting breaks locality, hammers caches and is every bit as non-deterministic as a garbage collector.

umanwizard

11 hours ago

> Distinguishing mutability has its advantages

I think it's misleading to say that Rust distinguishes mutability. It distinguishes _exclusivity_. If you hold a reference to something, you are guaranteed that nothing else holds an exclusive reference to it (which is spelled &mut). You are _not_ guaranteed that nothing accessible through that reference can change (for example, it might contain a RefCell or other interior-mutable type). Shared references (spelled &) usually imply immutability, but not always. On the other hand, if you hold an exclusive reference to something, you are guaranteed that nothing, anywhere, holds any kind of reference to it.

IMO, the fact that exclusive references are spelled "&mut", and often colloquially called "mutable references", was a pedagogical mistake that we're unfortunately now stuck with.

beeflet

8 hours ago

>IMO, the fact that exclusive references are spelled "&mut", and often colloquially called "mutable references", was a pedagogical mistake that we're unfortunately now stuck with.

You couldn't just roll out a change like alias &e to &mut and &s to &, and then have a compiler warning for using the old &mut or &?

umanwizard

8 hours ago

That’s technically possible, yes, but I really doubt there is any appetite to change basic syntax like that when it’s already so ingrained in everyone’s mind.

lll-o-lll

11 hours ago

> People waste time on trivialities that will never make a difference.

This is an aha moment as I read it. The complexity of your tools must be paid back by the value they give to the business you’re in.

johnnyanmac

8 hours ago

Really depends on the "difference". If a male a container crate that is Fer from shippable but gives me knowledge to land a Rust gig, was it a triviality?

ilrwbwrkhv

8 hours ago

This is daft logic. Your business itself has no value in the modern world. Your todo saas app is not needed. Of course this argument is faulty, so going one step back, what is valuable is in the eyes of the hacker. For a lot of people, including mine, the triviality is also part of the value chain.

pcwalton

9 hours ago

I actually used to agree that Rust generally wasn't good for high-level application code, but working with Bevy has made me change that opinion for certain domains. I simply haven't seen a system that makes automatically parallelizing all application logic (game logic, in this case) feasible, other than Bevy and other Rust-based systems. The trick is that the borrow check gives the scheduler enough information to automatically safely determine which systems can run in parallel, and that's very powerful. It's not that you couldn't do this in C# or whatever--it's that you won't without a system that helps express your intent and enforces that those declarations are up to date.

For applications that don't need high performance for the CPU code and aren't systems code, sure, Rust may not be a good choice. I'm not writing the server-side code for low traffic Web sites in Rust either.

tptacek

8 hours ago

Just so we're clear, your reference points for "good for high-level application code" are systems code and game engines? :)

pcwalton

8 hours ago

Games themselves, not game engines. Systems code, game engines, and games.

This isn't meant to be an exhaustive list--it's just the domains I have experience with that Rust was a good fit for. Lest it seem like I'm saying Rust is a good fit for everything I've done, I also worked on Firefox where the UI was JavaScript, and I wouldn't hurry to rewrite that code in Rust. Nor would I want the throwaway stuff I write in Python or Ruby to be Rust.

tptacek

8 hours ago

I'm just saying, games are exactly one of the things I would assume Rust would be a natural fit for. :)

hollerith

4 hours ago

>Rust would be a natural fit for

Did you leave out a "not" here?

tptacek

4 hours ago

No, I don't think so? I would have predicted games as a sweet spot for Rust. Most significant game projects are done in C++, and I look at Rust as basically obsoleting C++.

hollerith

4 hours ago

OK. Thanks.

My guess was that since almost no one will pay more for a game's having fewer security vulns, there is less benefit to incurring the expense of Rust (takes longer to learn, development speed is slightly less)

Yujf

an hour ago

Its not just vulnerabilities. In theory you should also get more stability.

For example I like to play Civ with a friend, but stopped because about once every 30 minutes one of us would have their game crash. If it was written in Rust, I assume it might be more stable.

tptacek

3 hours ago

When we talk about Rust being a reasonable choice for things like (say) a CRUD app, memory safety is already table stakes; every mainstream high-level language is memory-safe. Why would you ever pick Rust over Java? The answer to that question will be an even better answer to why you'd write a game in Rust.

drogus

9 hours ago

It's funny when people mention Go as the gold standard of not adding features to the language and Rust as ever-changing when Rust hasn't introduced any major changes in at least 3-4 years and Go introduced a major paradigm shift in how people structure their code (generics).

Before you start replying with "Rust introduced X" - ask yourself - is X extending an existing feature slightly or does it introduce an entirely new concept?

senorrib

8 hours ago

Generics is hardly a major paradigm shift, and these two languages are worlds apart in amount of features.

ilrwbwrkhv

8 hours ago

Ya the article is a bit fluffy and insubstantial. Surprising it's been voted up so highly on HN. Are people just going off the title?

jeffreyrogers

9 hours ago

I learned to program around the peak of object oriented fetishization. Shortly after that came functional programming's moment, and now it seems we are slightly past Rust and other safety focused languages' peak period of hype. All three language families have useful things to offer, but were never the panacea their proponents claimed them to be. "No Silver Bullet" continues to be true.

lacker

11 hours ago

I like Rust but at the same time I agree with the points here. These things are indeed problems with Rust.

Nevertheless, C++ has even worse problems. When your alternative is using C++, that's the time to consider Rust.

rich_sasha

11 hours ago

I think to some extent Rust is a victim of its own unreasonable effectiveness. It is great at its narrow niche of memory safe low level programming, but frankly pretty good at lots of other things. But at these other applications some of its design principles get in the way - like the pedantic borrow checker. Languages not used outside their niches don't tend to collect such criticism.

Python is a bit like that. It is a top choice for a few things, and ends up used effectively for other things, simply because it is versatile. But then people run into issues with dynamic typing, zero static safety, start slapping type annotations everywhere... and bemoan Python as a bit of a horror show.

My use case for Rust is complementing Python, where frankly I don't care about half the complex features, still it's nicer than C or C++ to code in. The complexities of the borrow checker are more like a tax to me. I understand people who are frustrated with it thought, as otherwise they see it as a bit of a perfect language.

throwawaymaths

10 hours ago

I think in general python gets used because of laziness and vitality. It's just the dumb shit that X person learned first because Y person before then was taught it because it was easy even though it's maybe not even the right choice for example, you can't properly write a working webserver in python without {venv, uvicorn, celery etc.} and if youve ever worked in another language its like why the hell is this shit here? Because it's viral, someone didn't know better, and it stuck.

Same goes for machine learning. The ML folks at the start couldn't be bothered to learn something the least bit sophisticated. Some things are getting better. You don't need conda anymore, tensorflow wheels are out, and at least instead of shippong around .pt, checkpoint, or pickle files at least we use safetensors, but there's still python shit around, like jinja2 templates for conversations, etc.

Anyways if we want good things we need to get better about getting unstuck from these local minima.

rich_sasha

10 hours ago

I disagree re Python. It is a brilliant, flexible scripting language. It is easy to build expressive libraries such as pytest or argparse, with deep introspection. It is easy to prototype by subtly changing return types, or even keeping them flexible. It is really easy to eg build a custom data type and build custom expression trees, such as what ML often needs.

It has a number of features (often stemming from the above) that make it a PITA for other applications, even when it would be fairly well suited to them otherwise. What I would give for proper static typing for production Python! Alas, that's not coming, and Rust's occasionally mind boggling borrow checker is there to stay.

throwawaymaths

8 hours ago

If you feel that way about python, it's really just likely you haven't tried anything else better.

And anyways you probably shouldn't be serving a website with a scripting language (php and perl are great examples of why not). You probably shouldn't be deploying ml with a scripting language (maybe training is fine, if you're not doing distributed training). You probably shouldn't have too many core os components in a scripting language lookin at you Ubuntu, you probably shouldn't write a cloud (openstack) using a scripting language. What happened to "right tool for the right job".

rich_sasha

2 hours ago

I don't think you're getting my point. It's a good scripting language - there may better ones, that's besides my point. And your heuristic is terribly wrong, I have used many languages, scripting and otherwise.

My point is, it's great at its niche and good but kind of clunky at other things it ends up used for. At its off-niche applications, it attracts a lot of criticism - like you talking about how it's a bad idea to serve a webpage from a scripting language or productionise ML models.

No one complains that C++ is clunky at, dunno, serving websites, simply because it is so ill suited for it that no one ever tries. But Rust is less obviously a bad choice. Still that attracts people who find it clunky when they "just" want to serve a webpage and don't want to deal with the vagaries of borrow checker.

ilrwbwrkhv

8 hours ago

People keep talking about the borrow checker. I have written over 70k lines in Rust so far and it hasn't really been that big of an issue. There are large-ish projects like Zed and Zellij in Rust which seem to be pretty straightforward code as well. I feel it's a bit overblown the whole borrow checker issue.

egnehots

11 hours ago

Some points resonate with me:

> People don't want "to have to play Chess against the compiler"

Things that are easy to express in other languages become very hard in Rust due to the languages constraints on ownership, async...

> Rust has arrived at the complexity of Haskell and C++, each year requiring more knowledge to keep up with the latest and greatest.

It's indeed hard to keep up.

> Async is highly problematic.

Yes, more complexity, more fragmentation and feel like another language.

But one point feels unfair:

> the excellent tooling and dev team for Rust [..] pulls the wool over people’s eyes and convinces them that this is a good language that is simple and worth investing in.

What? No. The main appeal was the safety. It's still a distinctive feature of Rust. To almost eliminate a whole class of safety issues. It has been proven by several lengthy reports such as https://security.googleblog.com/2024/09/eliminating-memory-s....

They are many projects for which the reliability and efficiency are worth the trouble.

dvektor

11 hours ago

I agree with a couple points here, specifically I agree that choosing a language based on it's community (and not it's ecosystem) is just silly. And we all know that async ended up being a bit of a thorn in rust's side.

But yeah, rust is very much a systems language: so it will be forcing you to think about memory layout one way or the other. Idk how valid of a complaint that is when you really consider that, and specifically the other alternatives you have.

tptacek

11 hours ago

A complication of the "Rust is a systems programming language" thing is that people adopt definitions of "systems" of varying expansiveness to suit the situation. There are unquestionable systems programming domains --- the kernel is a great example, and one where it's easy to see why Rust is an exciting proposition; same with browsers, the "second OS" everyone runs --- and then more questionable domains. Is the framework-layer code for a CRUD web application "systems" code? How about a container orchestrator?

This isn't a criticism of Rust, but rather of the framing we often use to compare Rust and (say) Python or Java.

nine_k

11 hours ago

Rust makes you think about your memory layout, memory allocation and avoiding thereof, about the specific time you grab and release other resources, about specifics of your inter-thread interactions, etc.

If such considerations are natural for your problem domain, you likely do "systems programming" and also happen know C, have an.opinion on Zig, etc.

If such considerations are the noise which you wish your language would abstract away, then you likely do "application programming", and you can pick from a wide gamut of languages, from Ruby and Python to Typescript to Elixir and Pony to C#, Java, and Kotlin to OCaml and Haskell. You can be utterly productive with each.

sophacles

10 hours ago

What does "think about your memory layout" mean? Can you provide an example? I've seen this brought up a few times on this thread and have no idea what people are referring to when they say it.

As for the rest of your list - I'm not sure why rust is special in regards to "the specific time you grab and release resources" or "inter-thread interactions". Seriously - I have to think about when I acquire and release resources like sockets and file handles python, c, ocaml, java, c#, and every other language I've used. Its not like you can randomly call file.close() or close(fd) (in python and c respectively) and expect to be able to continue reading or writing the file later. Same for inter-thread interactions... all those languages have mutexes too. Like none of that is rust-specific, its just the consequence of using resources and threads in code.

nine_k

3 hours ago

> What does "think about your memory layout" mean?

Here are some of the typical concerns:

- How exactly fields of a record sit in memory, how much room do hey take, taking into account things like padding for aligned access?

- Are related data sit next to each other, and can stay in the CPU cache together while needed?

- Are chaotic memory accesses thrashing the cache?

- Do the data structures avoid gratuitous references / pointer chasing (at least mostly)?

- Are local variables mostly allocated on the stack?

- Does your code avoid heap allocations where possible?

- Do fields in your data structure match a binary format, such as of an IP packet, or a memory-mapped register?

- Are your sensitive data protected from paging out to disk if free RAM is exhausted?

If these questions are not even relevant for your problem domain, you likely are not doing systems programming.

tptacek

9 hours ago

Again, the subtext here is GC versus direct control of memory lifecycles, and it is probably not reasonable to argue that there isn't a tradeoff here --- that every application is as gracefully expressible in one as the other, so long as you "git gud" at it. Both sides of this debate are guilty of deploying that trope.

sophacles

8 hours ago

I'm not arguing that there isn't a tradeoff, or about "git gud". I'm literally and genuinely baffled about how one can magically elide knowing if a file is open or closed (or the equivalent) when using a resource. Like I can't think of a single language that doesn't make you explicitly obtain resources, and most of the GC languages do the same thing as rust for casual closing - just let the handle go out of scope.

Even for memory, a huge amount of the rust I write isn't performance code - I don't understand why it's a mental burden to write

let x = vec![a, b, c];

When the equivalent in python is:

x = [a, b, c]

Nothing about either requires a lick of memory allocation thought, nor about memory layout. Sure in rust I have to think about what I'm going to do with that vec in rust and the mutation story up-front, but after enough lines of python I have also learned to think of that up front there too (ortherwise I know I'm going to be chasing down how I ended up mutating a copy of the list rather than the original list I wanted to mutate - usually because someone did list = $list_comprehension somewhere in the call stack before mutating).

I'm not being disingenuous here - I literally don't understand the difference, it feels like an oddly targetted complaint about things that are just what computer languages do. To the best of my ability to determine the biggest differences between the languages aren't about what's simple and complex, but how the problems with the complex things express themselves. I mean it's not like getting a recursion limit error in python on a line that merely does "temp = some_object.foo" is straight-forward to deal with, or the problems with "for _, x := range foo { func() { stuff with x } }" are easy to understand/learn to work with - but I don't see people running around saying you shouldn't learn those languages because there's a bunch of hidden stupid crap to wrap your head around to be effective. (and yes, i did run into both those problems in my first week of using the languages)

In all the languages there are wierd idioms and rules - some of them you get used to and some of them you structure your program around. Sometimes you learn to love it, and sometimes it annoys you to no end. In every case I've ever found it's either learn to work with the language or sign up for a world of pain, but if you choose the former everything gets easier. When a language makes something seem hard, but it seems easy in my favorite language, well, in that case I've discovered the complexity is there in both, but when it's hidden from me it limited my ability to see a vast array of options to explore and shown a whole new set of problem solving tools at my disposal.

I still don't know what people mean when they talk about "having to think about memory layout"... like seriously to me it's: Thinking about pointer alignment and how to cast one struct into another in C... something I've only had to think about once in any language across a fairly wide range of tasks. If this is what's being referred to, I'm baffled about how it's coming up so much, but i suspect this isn't what people mean, and I don't know what they actually do mean.

jcranmer

7 hours ago

> I still don't know what people mean when they talk about "having to think about memory layout"

The best example I'd give is the degree to which you have to ask yourself if you want to use String or if you want to use &str--is this struct, or this function, going to own the string or borrow it from somebody else? If you're borrowing it, who is owning it? Can you actually make that work (this is really salient for parser designs)?

Essentially in Rust, before you can really start on a large project, you have to sit down and plan out how the memory ownership is going to go, and this design work doesn't really exist in most other languages. Note that it's not inherently a good thing or a bad thing, but it is a potential source of friction (especially for small projects or exploratory tools where memory ownership might want to evolve as you figure out what needs to happen).

tptacek

6 hours ago

Wading in here a little bit, and I know you've thought about this --- I think it's reasonable to say that there are problem domains where it's a very good thing, and problem domains where it isn't.

I think a subtextual problem for Rust advocacy is that the places where it's a clear win are a small subset of all software problems, and that space is shrinking. Rust would, in that view of the world, be a victim of its success: it's the best replacement we have for C/C++ today, but the industry has moved sharply away from solving problems that way, and sharply towards solving them with Javascript.

(Deno is doing something smart here.)

dvektor

6 hours ago

The way memory allocation and management becomes part of the paradigm of how we write and structure programs, is actually something I really enjoy about rust. It's like how you can do the exact same thing in C++, using the same concepts and tools (for the most part) with different names, but it never felt the same, or as natural. It's definitely helped the way I think about programs as a whole.

tptacek

4 hours ago

I feel the same way when I implement reference counting in a C program. It's certainly clarifying and educational. I think it's hard to argue that it's the most expedient way to write a CRUD application, though. Sometimes the most expedient path isn't the most fun one.

tptacek

8 hours ago

Totally reasonable question. The issue isn't how hard it is to get the memory for the a vector, but rather what you have to do to store references to that vector elsewhere in your code, so that the compiler can prove its bounded lifetime and release resources without creating UAF bugs.

DiabloD3

11 hours ago

"Systems programming language" has almost turned into a weird slur; instead of using it to refer to languages that can actually handle that task, they use it to attempt to pigeonhole a language into only that.

As in, people don't realize being a "systems programming language" is extremely difficult to get right, and many languages simply can't handle that (and never will, as per internal design requirements unique to those languages); if a language gets that right, they're going to get everything else right too if people decided to use it for that.

tptacek

11 hours ago

See, depending on your definition of "systems programming language", that is just wildly false. A language that nails all the details and ergonomics of expressing a kernel block device driver is almost necessarily going to be suboptimal for exploratory scientific computing or line-of-business app development.

Again: this is about the term, not about the language. I don't think it's controversial to suggest that there is no one ur-language that is optimal for every problem domain!

DiabloD3

10 hours ago

I don't think the people that use it as a slur actually define it. They use it to mean the language they don't like because they think it has some level of enforced complexity that takes away from the language instead of being an important feature of the language.

tptacek

9 hours ago

Yes: it's about the distinction between global GC and programmer-defined memory management. GC is about as straightforward a tradeoff as you can make: remove a very large class of programmer concerns in exchange for a different performance envelope. It is not reasonable to argue that Rust's memory management doesn't represent a point on a tradeoff space --- that people suggesting GC languages are better fits for some problems just don't grok Rust well enough. That's a common trope, and it's pretty obviously false, just as it would be false to say that kernels should just supply a GC runtime so we can write device drivers in Java.

timeon

10 hours ago

Yeah I use often Rust where Python would be enough. But unless I really need quick/interactive feedback (for exploratory stuff ie.: Jupyter with plots), Rust suits me well.

tptacek

9 hours ago

I enjoy expressing applications in C. Once a week, a story hits the front page here about someone shipping a web app in C. C suits me well. But I don't pretend that's an objectively reasonable engineering decision. It is not.

henning

12 hours ago

> People waste time on trivialities that will never make a difference.

Depending on the situation, memory layout could be trivial (copying 200 bytes once at startup vs. not in a way that should never be user-perceptible and difficult to even measure) or actually a big deal (chasing down pointers upon pointers in a tight inner loop). It's entirely situational. To dismiss all of that as "trivial" and saying it will "never" make a difference is not helpful. There are a lot of shitty apps that are impossible to get running reasonably without a total rewrite and their shitty use of memory is part of that.

hyperbrainer

12 hours ago

Criticising a systems programming language for needing to manually manage memory is honestly embarrassing.

IgorPartola

11 hours ago

I mean to be fair so is using a systems programming language for every use case under the sun. If Rust is a great systems programming language that’s one thing. If it’s a general purpose language that’s another.

keybored

11 hours ago

A lot of git(1) subcommands were originally written in shell or Perl. Now most are written in C.

Through many decades people wrote utilities and applications in C. Not hardcore lower-level kernel modules. Just utilities and applications. Because that’s what they wanted to write them in. Over Perl or Java or whatever else the alternatives were.

What’s more C than that? Writing everything short of scripts in it?

Now people write applications in a modern programming language with modern affordances. They might be working uphill to a degree but they could have chosen much less ergonomic options.

The embarrassing part is criticizing people who have put in the work, not on the merits of their work, but on… having put in too much work.

hyperbrainer

11 hours ago

The two are not mutually exclusive. Also, I don't think I have ever needed to actively think about memory management more than .clone() and static for any hobby project I have undertaken. All the ML-like features like sum types, pattern matching etc. add great value. Cargo too. So, it is a great general purpose programming language. But blaming it as too low-level or similar despite choosing it is obtuse at best.

tptacek

11 hours ago

The subtext is that most of the time it won't make a difference, and Rust demands that you consider it every of the time. That squares with my experience. The powerful argument Rust has is that in the hotspots where memory lifecycle and layout make a huge difference to programs, it's much easier to express the fast and predictable memory arrangement than in GC'd languages.

andrepd

12 hours ago

Thinking like that is how we get 12MB of javascript to read a news article, or mobile apps that are jankier than Word 97.

I don't get how someone can criticise a systems programming language by saying "I have to think about memory layout"....

bachmeier

10 hours ago

There's a response to your comment in the post:

> I feel like Rust is self-defined as a “systems” language, but it’s being used to write web apps and command-line tools and all sorts of things.

> This is a little disappointing, but also predictable: the more successful your language, the more people will use your language for things it wasn’t intended for.

> This post still offends many who have tied Rust to their identity, but that’s their problem, not mine.

MuffinFlavored

10 hours ago

Who uses panic instead of `?` and anyhow / Box<dyn Error> (error propagation?)

I think there is even a (gross) way to achieve try/catch around a block of code that panics?

pshc

10 hours ago

Yeah, panic/assert is only for Things That Really Shouldn’t Ever Fail, If They Do Our Base Assumptions Have Broken.

whereas Error is for things that are unlikely to fail, like network/filesystem requests and recoverable logic bugs.

indulona

9 hours ago

i could buy an alphabet soup, add in some cereals, mix it up and throw it on the table, knowing it would end up looking indistinguishable from rust code.

IshKebab

12 hours ago

So much to disagree with....

> In practice, people just want to be able to write a tree-like type without having to play Chess against the compiler.

Sure, Rust's strong encouragement of tree-structured ownership may be annoying when you try and make a spaghetti ownership soup, but it's not like it doesn't have upsides. Many people have written about how the ownership & borrowing rules lead to code structure that has fewer bugs.

> I think that if you rewrite anything from scratch with performance in mind, you’ll see a significant performance improvement.

Maybe, but I think this is missing the point. The "rewrote it in Rust and it's X times faster" stories are generally when people rewrite from very slow (Python) or medium fast languages (JavaScript or maybe even Go).

In those cases you can rewrite in Rust without considering performance and get amazing speedups. I recently did a straight 1:1 port of some Python code with zero extra optimisation effort and got a 45x speedup.

Sure I maybe could have got the same in C or C++ but there's no way I would have rewritten it in C++ because fuck segfaults and UB. I don't want to spend any more of my life debugging that.

> Rust has arrived at the complexity of Haskell and C++, each year requiring more knowledge to keep up with the latest and greatest.

I don't really know about Haskell, but I don't think Rust's complexity is anywhere close to as bad as C++'s. Even if it were it doesn't matter because in Rust if you forget some complex rule the compiler will tell you, whereas in C++ it will randomly crash but only in release mode after the program has been running for 2 hours. Totally different.

> The “Friendly” Community

Gotta agree with this though. The "we're friendly" thing is bullshit.

> Async is highly problematic

Also agree here. Async is a huge wart on Rust's otherwise relatively unblemished face. Big shame. Oh well. You can mostly avoid it, and there are some cases where it's genuinely good (e.g. Embassy).

> I feel like Rust is self-defined as a “systems” language, but it’s being used to write web apps and command-line tools and all sorts of things. > > This is a little disappointing, but also predictable: the more successful your language, the more people will use your language for things it wasn’t intended for.

I don't see why he's disappointed about this. Rust is great for command line tools and web backends.

> I think that the excellent tooling and dev team for Rust, subsidized by Big Tech, pulls the wool over people’s eyes and convinces them that this is a good language that is simple and worth investing in. There’s danger in that type of thinking.

Ok this guy is not worth listening to.

tptacek

11 hours ago

First off, if you edit the "this guy is not worth listening to" out of your comment, you'll probably get better responses from people.

Second: I don't think this author disagrees with you that there are huge speedups to get from porting code out of Python. But you'd also get huge speedups porting to Java, and you wouldn't be in the business of managing your own memory lifecycles.

IshKebab

11 hours ago

I don't think that was too harsh given that he's saying that everyone who likes Rust (an extremely popular language) is an idiot who has been tricked into thinking it's good.

How can you take opinions like that seriously? It's like saying "nah The Beatles weren't actually that good, everyone just thought they were because of their cool sunglasses".

It's patronising and illogical and I don't think it's worth listening to nonsense like that.

tptacek

11 hours ago

He didn't say that at all.

IshKebab

2 hours ago

I literally quoted it:

> I think that the excellent tooling and dev team for Rust, subsidized by Big Tech, pulls the wool over people’s eyes and convinces them that this is a good language that is simple and worth investing in. There’s danger in that type of thinking.

Patronising and wrong.

VeejayRampay

11 hours ago

I'm curious what kind of code gets a 45x speedup by going from python to rust

and by that I don't mean the rhetorical or bait-style "i'm curious", no, the literal I'm curious, cause I'm trying to find use cases such as that these days and I'm often thwarted by the fact that for anything requiring remotely decent speeds, python most of the time already delegates to C extensions and so any rewrite is not as useful

jerf

11 hours ago

"I'm often thwarted by the fact that for anything requiring remotely decent speeds, python most of the time already delegates to C extensions and so any rewrite is not as useful"

Be sure you verify this is the case for whatever you think it is, though. Pure Python is so much slower than compiled languages (not just Rust) that you don't have to do much percentage-wise in pure Python before you've badly fallen behind in performance versus the pure-compiled alternatives.

I think this is asserted a lot more often then it is benchmarked. I am reminded of the way people for a long time asserted that the performance of web languages doesn't matter because you spend all your time waiting for the database, so it never mattered. People would just whip this argument out reflexively. It turns out that if you take a non-trivial codebase written in such a language and actually benchmark it, it is often not true, because as applications grow they tend to rapidly outgrow "all my code is just running a SELECT and slamming the results with minimal processing out to the web stream". I hear this a lot less often than I used to, probably through the slow-but-effective process of a lot of individuals learning the hard way this isn't true.

I've seen a lot of Python code. Very little of it that was not "data science" was just a bit of scripting around lots of large C-based objects, such that Python wasn't doing much actual work. And even some of that "data science" was falling back to pure Python without realizing because NumPy actually makes that shockingly easy.

Aeolos

11 hours ago

Anecdotal experience: we rewrote an image processing algorithm from numpy+scipy to pure rust and got a 50x speedup in release builds, without even spending any effort optimizing the rust side.

There are further improvements possible around memory allocation and cachelines, but 2 days for 50x improvement was sufficient to not make it worth investing additional effort.

Edit: this was from a team who had _never_ touched Rust before.

danudey

11 hours ago

This is an old example, but - date/time parsing.

A coworker of mine years ago was trying to parse out some large logfiles and it was running incredibly slowly (because the log file was huge).

Just for fun he profiled the code and found that 90% of the time was spent taking the timestamp ("2019-04-22 15:24:41") into a Python datetime. It was a slow morning, so we went back and forth trying to come up with new methods of optimizing this parsing, including (among other things) creating a dict to map date strings to datetime objects (since there were a lot of repeats).

After some even more profiling, I found that most of the slowdown happened because most of Python's strptime() implementation is written in Python so that it can handle timezones correctly; this prevented them from just calling out to the C library's strptime() implementation.

Since our timestamps didn't have a timezone specified anyway, I wrote my first ever C module[0] for Python, which simply takes two strings (the format and the timestamp) and runs them through strptime and returns a python datetime of the result.

I lost the actual benchmark data before I had a chance to record it somewhere to reproduce, and the Python 3 version in my repo doesn't have as much of a speedup compared to the default Python code, but the initial code that I wrote provided a 47x performance boost to the parsing compared to the built-in Python strptime().

Anyone who had a similar Python script and converted it wholesale to Rust (or C or Golang, probably) would have seen a similarly massive increase in performance.

[0] https://github.com/danudey/pystrptime/

jcgrillo

11 hours ago

One could argue that writing a timestamp as a string which then has to be parsed is silly and instead it should be delta-of-delta encoded and packed into variable width integers, but even then double integrating and constructing a datetime for each one would still be expensive in python, only less so.

cyberax

11 hours ago

> I'm curious what kind of code gets a 45x speedup by going from python to rust

Pretty much any code that is not just tying together external libraries?

tuveson

11 hours ago

If you heavily rely on the Python standard library, then you’re using a lot of Python code that doesn’t call out to C extensions. Peruse the standard library code, if you want to get a sense of it: https://github.com/python/cpython/tree/main/Lib

So you can expect any code that heavily relies on the standard library to be slower than the Rust equivalent.

A purely interpreted language implementation (not JIT’d) like CPython is almost always going to have a 10x-100x slowdown compared to equivalent code in C/C++/Rust/Go or most other compiled/JIT’d languages. So unless your program spends the vast majority of time in C extensions, it will be much slower.

Etherlord87

10 hours ago

Conway's Game of Life perhaps is a good example: it's a simple program, with a tight loop and cheap calculation in the loop. Python's loops are slow. I wouldn't be surprised if the speedup was much greater than 45x.

IshKebab

11 hours ago

It is basically reading a massive JSON file containing a few thousand logs and then scanning them with a load of regexes.

I was a bit surprised how much faster it was too. Apart from Python being dog slow the only thing I really changed was to use RegexSet which isn't available in Python. I didn't benchmark how much difference that made though; I just used it because it was obviously the right thing to do.

That's kind of the point. If you just do the obvious thing in Rust you get very good performance by default.

It's the same in C++ but then you're writing C++.

tialaramex

an hour ago

The actual regular expression implementation in Rust is going to be fast, but one of the things that caught a reddit poster out only recently was that the Rust regex crate's parser doesn't magically cache, so if you sit in a tight loop making the same regex over and over, it'll do all that work over and over, whereas the Python code might take ten times longer to do it once, then caches it, it doesn't take long for that to end up faster.

Now, if you're going to use RegexSet you're also smart enough to read "For example, it’s a bad idea to compile the same regex repeatedly in a loop" and say "Yeah, makes sense, I will not repeatedly compile the same regex". But some fraction of Python programmers won't read that - and it'll be very slow.

VeejayRampay

12 hours ago

rust is fine, it's a solid mix of performance and expressiveness, it has good constructs and it's gaining traction

it's hard to learn so we shall see what kind of niche it can carve for itself, but it's fine

brink

11 hours ago

> it's hard to learn

And as long as Rust remains popular, this is why we will witness endless complaining about it. Most devs are lazy, and would rather sweep complexity under the rug and pretend it doesn't exist until it becomes a real problem they can't ignore anymore. That's fine. But no need to be so vocal about it. At this point, people whining about Rust is more of a trope than people proselytizing it.

rastignack

11 hours ago

> Most devs are lazy, and would rather sweep complexity under the rug and pretend it doesn't exist until it becomes a real problem they can't ignore anymore

You mean pragmatic. Not all of us are memory absolutists. The time ideally invested in memory management really depends on the problem space, the deadlines, etc.

timeon

10 hours ago

> At this point, people whining about Rust is more of a trope than people proselytizing it.

This is common pattern reminds me cross-fit/veganism/i-use-arch/etc. Almost like an echo.

DiabloD3

12 hours ago

I've read this before, it's been passed around the Rust community a few times.

The annotated tl;dr is: Chris doesn't want to learn how hardware works, they don't want to learn how to write optimal software, they don't want to write safe software, they just want to write in a language they already know because they're not comfortable with learning other languages because their home language is a functional language (Haskell). It's a weird, yet short, essay that doesn't actually go anywhere.

I suspect Chris wrote the essay against their will, or because people asking them about Rust rubbed them the wrong way, because they lash out and say "This post still offends many who have tied Rust to their identity, but that’s their problem, not mine."

Its the Internet, man, if you're not offending someone, nobody is reading your shit.

awesome_dude

10 hours ago

So, we should be focused on attacking the author, not the points raised in the article?

tedk-42

11 hours ago

Surely someone who writes a lot of C code as he mentions has written it for hardware, no?

DiabloD3

11 hours ago

Take a gander at the rest of that blog, they're a Haskell main.

samatman

9 hours ago

Chris Done is male, is there some reason you're misgendering him in addition to making some extremely personal and out-there ad hominem comments insinuating various reasons not in evidence for why he posted what he did?

What's the play here?

Minor49er

11 hours ago

Chris is a team of people? I thought he was just one developer

mappu

11 hours ago

If you re-read the sentence with s/Chris/The Author/ I expect you'll find the pronoun cromulent. "They" was exclusively plural in Middle English in the 1300s, but, we're not speaking Middle English.

Narishma

11 hours ago

What makes you think they're a team?

Minor49er

7 hours ago

What else would you call them? A collective?