Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Rust is actually quite suitable for a number of domains where it was never intended to excel.

Writing web service backends is one domain where Rust absolutely kicks ass. I would choose Rust/(Actix or Axum) over Go or Flask any day. The database story is a little rough around the edges, but it's getting better and SQLx is good enough for me.

edit: The downvoters are missing out.



To me, web dev really sounds like the one place where everything works and it's more a question of what is in fashion. Java, Ruby, Python, PHP, C, C++, Go, Rust, Scala, Kotlin, probably even Swift? And of course NodeJS was made for that, right?

I am absolutely convinced I can find success story of web backends built with all those languages.


Yeah, "web services backend" really means "code exercising APIs pioneered by SunOS in 1988". It's easy to be rock solid if your only dependency is the bedrock.


> probably even Swift

It's possible to write web backends in Swift, but it's probably not a good idea. When I last did so, I ran into ridiculous issues all the time, such as lazy variables not being thread-safe, secondary threads having ridiculously small (and non-adjustable) stack sizes and there being generally absolutely no story for failure recovery (have fun losing all your other in-flight requests and restarting your app in case of an invalid array access). It's possible that some of this has been fixed in the last 5 years since I stopped working on that project, but given Apple's priorities, I somehow doubt that the situation is significantly better.


The bar for web services is low, so pretty much anything works as long as it's easy. I wouldn't call them a success story.

When things get complex, you start missing Rust's type system and bugs creep in.

In node.js there was a notable improvement when TS became the de-facto standard and API development improved significantly (if you ignore the poor tooling, transpiling, building, TS being too slow). It's still far from perfect because TS has too many escape hatches and you can't trust TS code; with Rust, if it compiles and there are no unsafe (which is rarely a problem in web services) you get a lot of compile time guarantees for free.


There are 3 cases. The first is that you are comfortable with Rust and you just choose it for that. The second is that you're not comfortable with Rust and you choose something else that works for you.

The third is the interesting one. When your service has a lot of traffic and every bit of inefficiency costs you money (node rents) and energy. Rust is an obvious improvement over the interpreted languages. There are also a few rare cases where Rust has enough advantages over Go to choose the former. In general though, I feel that a lot of energy consumption and emissions can be avoided by choosing an appropriate language like Rust and Go.

This would be a strong argument in favor of these languages in the current environmental conditions, if it weren't for 'AI'. Whether it be to train them or run them, they guzzle energy even for problems that could be solved with a search engine. I agree that LLMs can do much more. But I don't think they do enough for the energy they consume.


> Rust is an obvious improvement over the interpreted languages.

Do we agree that most of the languages I mentioned above are not interpreted languages? You seem to only consider Go as a non-interpreted alternative...


I replied using my phone and couldn't see your original comment for reference. Yes, your list contains more compiled languages.

Of those, I'm not very comfortable with using C and C++ for backend development. Their lack of automated memory safety measures is an issue for services that are exposed to the internet. (To be clear, memory safety isn't the only type of safety required). Swift may be a fine choice. (I'm unfamiliar with it.)

JVM languages like Java, Kotlin and Scala are all compiled languages, but I'm unsure how well they satisfy what I said before. To repeat, what matters is energy efficiency and resource utilization (not speed). I hope that somebody can provide an insight into how much overhead they incur on account of running in a VM.


Other than Go it's just C/C++ and Swift.


Java, Scala and Kotlin too.


Those are interpreted.


You are one of those people stuck in the 90s, then.

Take 5 min to read about JIT and AOT compilation.


What point are you trying to make? V8 has a JIT compiler too, does that make JavaScript a compiled language?


If you run JavaScript with a JIT compiler, you can't say "it is slow because it is interpreted". And it is obviously wrong to say "V8 is slow because it is an interpreter", isn't it?


Perhaps. But a comparable Rust backend stack produces a single binary deployable that can absorb 50,000 QPS with no latency caused by garbage collection. You get all of that for free.

The type system and package manager are a delight, and writing with sum types results in code that is measurably more defect free than languages with nulls.


Yep, that's precisely it! When dealing with other languages I miss the "match" keyword and being able to open a block anywhere. Sure, sometimes Rust allows you to write terse abominations if you don't exercise a dose of caution and empathy for future maintainers (you included).

Other than the great developer experience in tooling and language ergonomics (as in coherent features not necessarily ease of use) the reason I continue to put up with the difficulties of Rust's borrow checker is because I feel I can work towards mastering one language and then write code across multiple domains AND at the end I'll have an easy way to share it, no Docker and friends needed.

But I don't shy away from the downsides. Rust loads the cognitive burden at the ends. Hard as hell in the beginning when learning it and most people (me included) bounce from it for the first few times unless they have C++ experience (from what I can tell). At the middle it's a joy even when writing "throwaway" code with .expect("Lol oops!") and friends. But when you get to the complex stuff it becomes incredibly hard again because Rust forces you to either rethink your design to fit the borrow checker rules or deal with unsafe code blocks which seem to have their own flavor of C++ like eldritch horrors.

Anyway, would *I* recommend Rust to everyone? Nah, Go is a better proposition for a most bang for your buck language, tooling and ecosystem UNLESS you're the kind that likes to deal with complexity for the fulfilled promise of one language for almost anything. In even simpler terms Go is good for most things, Rust can be used for everything.

Also stuff like Maud and Minijinja for Rust are delights on the backend when making old fashioned MPA.

Thanks for coming to my TED talk.


>Anyway, would I recommend Rust to everyone?

For me it's a question of whether I can get away with garbage collection. If I can then pretty much everything else is going to be twice as productive but if I can't then the options are quite limited and Rust is a good choice.


What language are you using that doesn’t have match? Even Java has the equivalent. The only ones I can think of that don’t are the scripting languages.. Python and JS.


Does Java have sum types now?


Yes via sealed classes. It also has pattern matching.


So they are there, but ugly to define:

    public abstract sealed class Vehicle permits Car, Truck {
      public Vehicle() {}
    }

    public final class Truck extends Vehicle implements Service {
      public final int loadCapacity;

      public Truck(int loadCapacity) {
        this.loadCapacity = loadCapacity;
      }
    }

    public non-sealed class Car extends Vehicle implements Service {
      public final int numberOfSeats;
      public final String brandName;

      public Car(int numberOfSeats, String brandName) {
        this.numberOfSeats = numberOfSeats;
        this.brandName = brandName;
      }
    }

In Kotlin it's a bit better, but nothing beats the ML-like langs (and Rust/ReScript/etc):

    type Truck = { loadCapacity: int }
    type Car = { numberOfSeats: int, brandName: string }
    type Vehicle = Truck | Car


You could use Java records to make things more concise:

  record Truck(int loadCapacity) implements Vehicle {}
  record Car(int numberOfSeats, String brandName) implements Vehicle {}
  sealed interface Vehicle permits Car, Truck {}


Scala 3 has:

  enum Vehicle:
    case Truck(loadCapacity: Int)
    case Car(numberOfSets: Int, brandName: String)


You implemented this much more verbosely than needed

    sealed interface Vehicle {
        record Truck(int loadCapacity) implements Vehicle {}
        record Car(int numberOfSeats, String brandName) implements Vehicle {}
    }


Ah! Thanks, I didn't know that. I should have RTFMD better - https://docs.oracle.com/en/java/javase/21/language/sealed-cl...

Turns out you can do this and not have the annoying inner class e.g. Vehicle.Car too:

  package com.example.vehicles;

  public sealed interface Vehicle
      // The permits clause has been omitted
      // as its permitted classes have been
      // defined in the same file.
  { }
  record Truck(int loadCapacity) implements Vehicle {}
  record Car(int numberOfSeats, String brandName) implements Vehicle {}


I think Java 21 does. Scala and Kotlin do as well.


Python has it as well.


Ah my mistake. It’s been at least 5 years since I’ve written it. I’m honestly surprised that JS has moved no where on it considering all of the fancy things they’ve been adding.


It has been proposed, but since there is all the process on how features get added into the standard, someone needs to champion it, and then there is the "at least two implementations" factor.

https://github.com/tc39/proposal-pattern-matching


Yeah, anything with nulls ends up with Option<this> and Option<that> which means unwraps or matches. There is a comment above about good bedrock and Rust works OK with nulls but it works really well with unsparse databases (avoiding joins).


Tokio + Axum + SQLx has been a total game-changer for me for web dev. It's by far the most productive I've been with any backend web stack.


I prefer rusqlite over SQLx; the latter is too bloated.


People that haven't tried this are downvoting with prejudice, but they just don't know.

Rust is an absolute gem at web backend. An absolute fucking gem.


We know, it stil isn't at Spring/ASP.NET level, coupled with Scala/Kotlin/F#.


I hate Spring(Boot): too much magic due to overuse of annotations.

On the JVM I'd prefer Kotlin/http4k/SQLDelight any day over {Java,Kotlin}/Spring(Boot)/{Hibernate,sql-in-strings}.


Because macro magic, or compiler plugins, is so much better, I guess.


What do you mean? Where are the "macro magic or compiler plugins"?


Most Rust frameworks, which was the point of this thread,

> Rust is an absolute gem at web backend. An absolute fucking gem.


Nothing beats vertx on JVM!


Curious, do you mind going into more detail on why?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: