Hacker News new | ask | show | jobs
by bigtimesink 476 days ago
This, but I'm getting tired of people using Rust for things that really should be in C# or Java.
1 comments

"really should be" ?

"in C# or Java" ?

where do you even base these claims? Do you know what C# and Java threads have that Rust doesn't? data races. And don't get me stated on the biggest paradigm failure that is OOP.

Projects I've seen at work. Projects posted on Hacker News. Data races aren't usually an issue for backend services, and modern Java/C# is multi-paradigm.
> Data races aren't usually an issue for backend services

I beg to differ unless all your logic is in the database with strong isolation guarantees.

Speaking of C# for backends that are using EF actively, I bet there are bugs in pretty much all of them caused by incorrect applications of optimistic concurrency.

Both have a garbage collection though that lead to higher developer productivity than compared to rust's affine types.
> higher developer productivity

Where have you been the past 5 years? Rust developers are insanely productive.

Can we put this myth to rest already? Rust being an "unproductive language" is thoroughly dis-proven.

There are domains where C# (and F#) productivity stems from similar reasons why writing a game in something that isn't Rust might be more productive without even sacrificing performance (or, at least, not to the drastic extent).

I can give you an example:

    var number = 0;
    var delay = Task.Delay(1000);

    for (var i = 0; i < 10; i++)
    {
        Task.Run(() =>
        {
            while (!delay.IsCompleted)
            {
                Interlocked.Increment(ref number);
            }
        });
    }

    await delay;
How would you write this idiomatically in Rust without using unsafe?

To avoid misunderstanding, I think Rust is a great language and even if you are a C# developer who does not plan to actively use it, learning Rust is of great benefit still because it forces you to tackle the concepts that implicitly underpin C#/F# in an explicit way.

There's a few things here that make this hard in Rust:

First, the main controller may panic and die, leaving all those tasks still running; while they run, they still access the two local variables, `number` and `delay`, which are now out of scope. My best understanding is that this doesn't result in undefined behavior in C#, but it's going to be some sort of crash with unpredictable results.

I think the expectation is that tasks use all cores, so the tasks also have to be essentially Send + 'static, which kinda complicates everything in Rust. Some sort of scoped spawning would help, but that doesn't seem to be part of core Tokio.

In C#, the number variable is a simple integer, and while updating it is done safely, there's nothing that forces the programmer to use Interlocked.Read or anything like that. So the value is going to be potentially stale. In Rust, it has to be declared atomic at the start.

Despite the `await delay`, there's nothing that awaits the tasks to finish; that counter is going to continue incrementing for a while even after `await delay`, and if its value is fetched multiple times in the main task, it's going to give different results.

In C#, the increment is done in Acquire-Release mode. Given nothing waits for tasks to complete, perhaps I'd be happy with Relaxed increments and reads.

So in conclusion: I agree, but I think you're arguing against Async Rust, rather than Rust. If so, that's fair. It's pretty much universally agreed that Async Rust is difficult and not very ergonomic right now.

On the other hand, I'm happy Rust forced me to go through the issues, and now I understand the potential pitfalls and performance implications a C#-like solution would have.

Does this lead to the decision fatigue you mention in another sub-thread? It seems like it would, so I'll give you that.

For posterity, here's the Rust version I arrived at:

    let number = Arc::new(AtomicUsize::new(0));
    let finished = Arc::new(AtomicBool::new(false));

    let finished_clone = Arc::clone(&finished);
    let delay = task::spawn(async move {
        sleep(Duration::from_secs(1)).await;
        finished_clone.store(true, Ordering::Release);
    });

    for _ in 0..10 {
        let number_clone = Arc::clone(&number);
        let finished_clone = Arc::clone(&finished);

        task::spawn(async move {
            while !finished_clone.load(Ordering::Acquire) {
                number_clone.fetch_add(1, Ordering::SeqCst);
                task::yield_now().await;
            }
        });
    }
    
    delay.await.unwrap();
https://play.rust-lang.org/?version=stable&mode=debug&editio...
I am not sure what are you trying to represent with this example, but here is the exact same thing without any unsafe:

use rayon::prelude::*;

use std::time::{Instant, Duration};

use std::sync::atomic::{AtomicUsize, Ordering};

fn main() {

    let finish_at = Instant::now() + Duration::from_secs(1);

    let number = AtomicUsize::new(0);

    (0..10).into_par_iter().for_each(|_| {
        while finish_at > Instant::now() {
            number.fetch_add(1, Ordering::Relaxed);
        }
    });
}

You can make it even simpler if you would use Mutex instead of atomics. Atomics are more performant though.

> How would you write this idiomatically in Rust without using unsafe?

Channels and selects. It's trivial.

Please post a snippet.
Even when it's used by mediocre developers, which is probably more than 90% of us, myself very much included? All I've been seeing is Rust being used by very enthusiastic and/or talented developers, who will be productive in any language.
> Rust developers are insanely productive.

If your baseline is a language that is missing some features that were in standard ML, sure. If you were already using OCaml or F#, Rust doesn't make you any more productive. If you were already using Haskell or Scala, Rust's lack of HKT will actively slow you down.

Longer compile times prolong iterative programming processes and having to take care of memory management through linear types adds restrictions on how you can express code and leads to additional mental burden. This can be part of a trade-off, where you get things in return (no runtime/gc), but your typical web app I don't see much advantages.
Rust is the silver bullet we all been waiting for?
No, that's the other end of the stick. Its en par with other languages
Well, put any language against Rust and Rustaceans would argue Rust is better than those languages so ... Silver bullet no?