logoalt Hacker News

Animatsyesterday at 9:07 PM22 repliesview on HN

I could see migrating from C or C++ or Python to Rust, for various reasons, but for web back-end work Go is a good match. I write almost entirely in Rust, but the last time I had to do something web server side in Rust, I now wish I'd used Go.

The OP points out the wordyness of Go's error syntax. That's a good point. Rust started with the same problem, and added the "?" syntax, which just does a return with an error value on errors. Most Go error handling is exactly that, written out. Rust lacks a uniform error type. Rust has three main error systems (io::Error, thiserror, and anyhow), which is a pain when you have to pass them upward through a chain of calls.

(There are a number of things which tend to be left out of new languages and are a pain to retrofit, because there will be nearly identical but incompatible versions. Constant types. Boolean types. Error types. Multidimensional array types. Vector and matrix types of size 2, 3, and 4 with their usual operations. If those are not standardized early, programs will spend much time fussing with multiple representations of the same thing. Except for error handling, these issues do not affect web dev much, but they are a huge pain for numerical work, graphics, and modeling, where standard operations are applied to arrays of numbers.)

Go has two main advantages for web services. First, goroutines, as the OP points out. Second, libraries, which the OP doesn't mention much. Go has libraries for most of the things a web service might need, and they are the ones Google uses internally. So they've survived in very heavily used environments. Even the obscure cases are heavily used. This is not true of Rust's crates, which are less mature and often don't have formal QA support.


Replies

swiftcodertoday at 6:21 AM

> Rust has three main error systems (io::Error, thiserror, and anyhow), which is a pain when you have to pass them upward through a chain of calls

anyhow explicitly isn't designed for what you are trying to do here. It's designed to be the last link in the chain (and complementary to thiserror, not in competition). If you are using anyhow any deeper than your top-level binary crate, you are likely to be in for an unpleasant time.

show 2 replies
mountainrivertoday at 4:17 AM

I love Go and used to write it heavily for anything non LLM based.

Now that we have agentic coding I just write everything in Rust and couldn’t be happier. The struggle with rust was writing it, go was made so it was easy to write for mid level engineers. Now that we have agentic coding I’m not sure Go’s value prop holds up anymore

My rust services have been nothing short of amazing from a performance and reliability perspective

show 7 replies
lionkoryesterday at 9:12 PM

> Rust lacks a uniform error type

Rust has practically one error, it's the Error trait. The things you've listed are some common ways to use it, but you're entirely fine with just Box<dyn Error> (which is basically what anyhow::Error is) and similar.

show 2 replies
fpolingyesterday at 9:43 PM

For me the main advantage of Go over Rust is compilation speed. Then compared with Go Rust still rely on many C and C++ libraries making it problematic to cross-compile or generate reproducible builds or static binaries.

The minus side of Go is too simplistic GC. When latency spikes hit, there are little options to address them besides painful rewrite.

show 3 replies
the__alchemistyesterday at 9:41 PM

I agree! The line early on about this being for backend services caught my attention. I love the Rust language and use it for embedded firmware and PC applications, but still use Python for web backends, because Rust doesn't have any tool sets on the tier of Django (Or Rails). It has Flask analogs, without the robust Flask ecosystem. I have less experience with Go, but would choose it over Rust for web backends, for the same reason you highlight: The library (including framework) ecosystem. I am also not the biggest Async Rust fan for the standard reasons (The rust web ecosystem is almost fully Async-required).

show 1 reply
atombenderyesterday at 11:03 PM

For backend web dev, there are advantages. I really like Axum's use of typing:

    pub async fn dataset_stats_handler(
        Path(dataset_id): Path<String>,
        Query(verbose): Query<bool>,
    ) -> impl IntoResponse {
      ...
    }
With a route like:

    .route("/datasets/{dataset_id}/stats", get(dataset_stats_handler))
…the "dataset_id" path variable is parsed straight into the dataset_id arg, and a query string "verbose" is parsed into a boolean. Super convenient compared to Go, and you type validation along with it.

Many other things to like: The absence of context.Context, the fact that handlers can just return the response data, etc.

What I don't like: Async.

show 3 replies
iknowstuffyesterday at 9:11 PM

Rust does not have three error systems. It has one: the Error trait. io::Error is one of many that implement it (nothing special about it). Errors defined via thiserror also implement it.

“Anyhow” just allows you to conveniently say “some Error” if you don’t care to write out an API contract specifying types of errors your function might spit out.

show 1 reply
mikeocoolyesterday at 9:54 PM

I was a big fan of go for a while. Though now that I have programmed more swift and rust recently, having a compiler that doesn’t protect against null pointer deferences or provide concurrency safety guarantees feels a little prehistoric.

Though go certainly did a much better job than rust on the standard library front.

show 1 reply
pjmlptoday at 5:04 AM

For me going from JVM and CLR ecosystem of programming languages into Go for backend development is a downgrade.

The language design makes sense in the context of Oberon (1987), and Limbo (1995).

Now when there are so many options finally building on top of Standard ML, and Lisp heritage, having to settle with Go feels like a downgrade.

I code since 1986, if I wanted if boilerplate error handling, or having cost as the only mechanism to declare constant values, there have been plenty of options.

vorticalboxtoday at 8:54 AM

I don't fully get the argument about errors.

in rust say a function returns Result<T, E> so either the we get a result all an error how is that different from (int, err) in go?

do you not still need to handle the error?

in go you just return the error up to whatever the top caller is.

show 2 replies
apatheticoniontoday at 12:50 PM

I use Rust for web services all the time. It's a dream compared to Go (which I wrote professionally for years).

At this point, I can't imagine a scenario not to use Rust for writing a web API.

throwaway2037today at 2:52 PM

What is "formal QA support"?

tertasrfgtoday at 2:05 AM

The funny thing is: All Rust source code looks like an assembly syntax error.

show 1 reply
malcolmgreavestoday at 3:43 PM

> Rust lacks a uniform error type.

Not quite true. The unifying error trait is std::error::Error.

> pain when you have to pass them upward through a chain of calls

Kind of? You just make an enum with the various variants that need to be passed through and use the #[from] macro to generate the conversion code automatically.

It’s more characters than eg. A union type in Python or TypeScript, but it’s not much more.

Plus, it makes you think about your error design, which is important!

christophilustoday at 11:36 AM

I just hate how many dependencies you have to pull in for a typical Rust project vs Go. As far as Go being an ugly language, there are some interesting wrappers that put lipstick on that pig such as https://lisette.run/

But personally, I don’t mind Go at all. I’ve even begun to prefer it for some things. That may be Stockholm syndrome, though.

show 2 replies
LoganDarkyesterday at 11:03 PM

thiserror and anyhow are just std::error with extra steps. Note that io::error is just a specific std::error.

The entire point in Rust is that you wrap Error impls with other Error impls, or translate one impl into another using a match. I've found this is far more flexible and verifiable than most other languages, because if you craft your error types with enough rigor, you can basically have a complete semantic backtrace without the overhead of a real backtrace.

I use thiserror a lot to help with my impls. Notably, all it does is impl Display and Error. It's not a specific other paradigm because it basically compiles out, it's just a macro.

Anyhow is perhaps the closest one to another paradigm because it allows you to discard typed information in favor of just the string messages, but it still integrates well with Errors (and is one).

innocentoldguyyesterday at 10:53 PM

I find Elixir's memory and threading models much more compelling than Go's for web services. There are many great libraries for Elixir as well, but if you need something else, Elixir makes rolling your own libraries very easy. I'd recommend giving Elixir a try, if you haven't already.

show 1 reply
Ygg2today at 7:56 AM

Go also has one glaring disadvantage. GC. Assuming you're in the cloud.

It's easy to write code that trivially eats memory. Plus any resources spent on it, are resources not spent on other cloud provider things.

DeathArrowtoday at 10:34 AM

>I could see migrating from C or C++ or Python to Rust, for various reasons, but for web back-end work Go is a good match. I write almost entirely in Rust, but the last time I had to do something web server side in Rust, I now wish I'd used Go.

Now there is a cult of rewriting everything in Rust. System level software? Yes. Web? I prefer not to.

runhelmtoday at 2:35 AM

[flagged]

LtWorfyesterday at 9:33 PM

Praising go for how it handles errors, when it's even worse than C where the compiler at least warns you if you're ignoring return values of calls. That's a new one.

show 1 reply