Hacker News new | ask | show | jobs
by ultimaweapon 437 days ago
For me lack of language specification is not a problem and it is good that Rust only have one implementation so I don't have a headache to support multiple compilers like C++. The only problems I have with trait is lack of const function and trait upcasting, which just solved by 1.86 that released yesterday. For iterator type mismatched it does not cause much problem since I can create a dedicated generic function to handle that.

The major problem for me with Rust is deadlock. In Rust it is very easy to cause a deadlock compared to other languages. In other languages you need to think a lot before locking a mutex but in Rust you just `foo.lock().unwrap()`, which can easily cause a deadlock if you have multiple mutexes and someone in your team does not aware the lock order.

4 comments

Sharing resources is always a source of deadlocks and bugs, I don’t see a feasible resolution to that in a programming language. I don’t think one gets into deadlocks more often than any other language with Rust, but you are not experiencing most other concurrency bugs, which makes it feel like deadlocks are a bigger issue.
Wait, I've been told by "evangelists" that besides not having any security vulnerabilities, you also can't have deadlocks in Rust!
No, you don't have data races in Rust. Deadlocks are more or less just as possible in Rust as in other languages. In fact, the 2024 edition of Rust changed something[0] to make it more difficult to hit some deadlock situations, but it's well-known that there's not much in the language to protect you from them.

[0] https://doc.rust-lang.org/edition-guide/rust-2024/temporary-...

Those "evangelists" would be wrong, then. Rust prevents data races by default, but doesn't prevent deadlocks by default. It is possible to use Rust's type system to statically ensure the lack of deadlocks [0], but that's not provided by default.

[0]: e.g., https://docs.rs/lock_ordering/latest/lock_ordering

I should have bookmarked the HN post that said it :)

It was one of the usual "if you'd have rewritten it in rust you'd have had no problems" posts. But instead of the usual memory safety list, they also added no deadlocks to the benefits.

Hey now Rust is also garbage collected:

https://news.ycombinator.com/item?id=43555249#43592602

I wonder what they'll add to it by tomorrow...

I think that's more a case of unnecessary pedantry. Rust "has garbage collection" in that you can opt in to the lifetime of some objects being handled by some kind of garbage collection. Rust doesn't "have garbage collection" in that Rust does not require a GC'd runtime to implement its semantics in a memory-safe manner. Two different concepts with similar terminology.

Edit: Also looking at that commenter's history I am rather skeptical they would reasonably be considered a "Rust evangelist"

As others have said, Rust's ownership model prevents data races, as it can prove that references to mutable data can only be created if there are no other references to that data. Safe Rust also prevents use-after-free, double-free, and use-uninitialized errors. Does not prevent memory leaks or deadlocks.

It's easy to write code that deadlocks; make two shared pointers to the same mutex, then lock them both. This compiles without warnings:

    let mutex_a = Arc::new(Mutex::new(0_u32));
    let mutex_b = mutex_a.clone();
    
    let a = mutex_a.lock().unwrap();
    let b = mutex_b.lock().unwrap();
    println!("{}", *a + *b);
You can use the parking_lot mutex implementation crate, which includes support for deadlock detection. Personally, I also try to avoid using Tokio's async mutexes.
Tokio mutexes are only useful if a lock needs to be held across suspension points. Since futures can migrate threads between suspension points and most regular mutexes on most platforms do not support being unlocked from a different thread, tokio’s mutex has a very narrow but a well defined use case.
Another use for tokio's mutexes is that they won't block a thread while waiting to acquire the lock (as awaiting a tokio mutex is itself a suspension point). For some use-cases this might not matter, though.
Could you create a type around Mutex that enforces the locking order?
You could - and this is what we do - push all of your state into one large struct. Note that this has drawbacks as well and if you have a lot of reads and some very important writes, you will still get deadlocks.
Open source implementation > open standard every time.

C++ is from an era open source was not yet well established.