Comment by Animats
20 hours ago
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.
> 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.
He was talking about the chain of function calls not crates. You still have that in your top level crate.
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
In my experience LLMs (I speak mainly of Claude Code & Cursor) write very poor quality Rust.
They treat it like it's JavaScript, falling back to using String/&str needlessly instead of making new types. They do ugly `static Mutex<Refcell<` a-la global JS variables for info sharing instead of working out the lifetimes to do it properly. It loves making functions infallible and then panic-ing within them and certainly I wouldn't use them for unsafe at all - they hallucinate safety comments which are in fact, totally unsound.
Of course these are all surmountable with an experienced developer to regularly step in and unfuck the code, but forcing them into 'harder' territory where every problem is not solved by a .clone() and an Arc<Mutex<>> means they will spend minutes 'thinking' about basic lifetime issues until I step in and add the missing `move` in a closure.
That is interesting. I make LLMs write C with the general hope that a simpler language they can manage well. That is not entirely true, though. They reason about C fluently indeed. The problem is, Claude pumps lots of bad C into the codebase if left unattended for 5 min. So, I need some clean-up passes afterwards to get to some acceptable quality level (both by LLMs and my own eyes). At which point, Claude sees the problem clearly, for some mysterious reason. Also, I use a C dialect heavly influenced by Go (slices, generics, no smart tricks, virtually no malloc).
LLMs generally write poor quality anything. It'll [usually] work, but it'll need massive refactoring to get in a maintainable and efficient state.
You gotta know how to write Rust (and general software arch) first. LLMs + Rust have been great for me.
"Write an SQL Repository with this interface"
Sweet - no need for SQLc or an ORM
same experience. any good claude skills to ease the pain?
1 reply →
Maybe true 6 months ago, but now it's better than any Rust Dev, as long as you guide it and not just let it rip on a full service/app unsupervised.
1 reply →
For me the bottleneck now is reading/reviewing code, not writing code. As you said, AI makes it way easier to write, but do you not review the code? And isn't a verbose, cryptic language with lots of nitty gritty memory management not harder to read/review?
I'm not sold on Rust being a great language to use with AI unless the reason to use it is a lot more than just Rust being fashionable.
I find Go harder to review than Rust.
The verbose error handling diluting the interesting parts is one thing, but the main issue is the weak type system. Having to read the callee's code to check if it deviates from `res xor err`, or if it mutates its arguments. Figuring out which interface that `func (o *Obj) ()` is implementing, if any. Dealing with documentation that is a wall of 100 disappointing oneliners all repeating the function name.
Rust is information-dense and takes longer to master, but it's not inherently cryptic, there's a finite amount of things to know. Memory management sometimes take a bit of thought to write, but it's straightforward to review, you can trust it's correct if it compiles, you just keep an eye out for optimizations.
1 reply →
In my experience, Rust is only mildly unpleasant to review, if only because the GitHub PR review interface is not an IDE. It can be hard to tell why .as_ref()s and whatnot had to be used without being able to hover over a variable to see its type. This is probably because of the language's preference for type inference, though personally I would rather that than having to skim over explicit types.
Compared to Rust, Go as a language requires a lot more effort to review. You have to be on the lookout for basic gotchas like not checking if a pointer is nil, placing `defer` in the wrong place, using a result when err isn't nil, and so on. Plus, diffs are messier because unused variables are a compilation error, and _, err := can change into _, err = solely due to new lines above.
1 reply →
It's the same logic for human and for AI code: In Rust the compiler catches many bugs so you don't have to.
If the LLM gives you safe code you know there are entire classes of things you don't have to review for.
That said, I agree with you. My experience is that LLMs are great if you are highly competent in the domain in which you let them work. And it's probably easier to be competent in Go than in Rust.
4 replies →
The build time and space for rust is awful for fast iteration e.g change a thing, verify.
Reading the code? Who has the time.
Aah, I am sure the chickens of vibe coded origin, will never come to roost.
2 replies →
IMO neither Go nor Rust are great for reading/reviewing code.
Go is too verbose and the type system isn't expressive enough. Rust code is littered with little memory management details and it requires tons of third party libraries.
I think coding agents will eventually be able to get the low level details right on their own. Reviewers should be able to focus on architecture, design and logic mistakes.
I also think we need a high level formal specification language to tell agents what we expect them to do.
6 replies →
The benefit is if you lean heavily on types then successful compilation is a massive indicator in the feedback loop. Using stop hooks to ensure successful compilation after every iteration is a game changer. Go also has compilation of course but because the type system is so much more robust in Rust the compilation guarantees so much more about the behaviour of your program. You end up just code reviewing the shape and flow of data.
4 replies →
Go was never about being easy to write (thought it is), but it was always about being easy to read and it is, by far, the easiest language to read that I've ever used (and throughout the decades, I went through Basic, Pascal, C, Java, JavaScript, C#, TypeScript, Ruby and Python). That becomes even more important if you are not writing the code yourself...
it's too verbose, yet not explicit.
you need to know the conventions to spot what's not there (did you miss the error handling? or the magic comment for the whatever codegen serializer? c'est la vie!)
edit: just a few comments below an even better description of what I'm trying to convey: https://news.ycombinator.com/item?id=48264853
1 reply →
[dead]
> The struggle with rust was writing it, go was made so it was easy to write for mid level engineers.
In practice, anything that makes it easier for humans to program also makes it easier for LLMs to program.
You also wont typically learn that the LLM is close to the limits of understanding your code base until after it has blown past it's own capabilities, leaving you with a mountain of code that you are not skilled enough to fix.
Java, C# are good choices as they tend to enforce a certain structure. Go, good because it's very readable even if you dont know the language.
C++, Rust are poor choices unless you are already a senior in that language.
Go is really easy to read and write, even if Go's philosophy means that some of that feels clunky because it's less featureful than other languages. It makes up for it with a comprehensive stlib that makes it trivial to build services with few to no third party dependencies.
I don't think the value prop has changed at all there. One day the AI gravy train will stop and people who used AI to punch above their weight will no longer be able to debug the stuff they built unless they put in the hard work of learning the language.
Nothing to worry about with Go in that respect because of how much it's been designed to be simple. Even the annoying err/nil checks you need to do all the time are in service of that simplicity. It gets old fast but it leaves nothing to the imagination.
The value prop of Go in not on writing, but in reading and comprehension by people different from the autor(s). For systems expected to last some years, this translates in reduced total cost of maintenance over the life of the system (in my experience typically 80% or more of the total cost) and facilitating traspassing maintenance to diferent people than the authors. In use cases where Go has "good enough" performance, for backend systems with business logic and small amount of "bare metal" programming, I recommend Go to teams instead of Rust. When extreme performance and reduced memory footprint is more important than the other properties, Rust is better than Go.
>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
Agents seem to have a better time with Go. Humans need to review the agents outputs and in general they have an easier time to do it with Go.
> 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.
Having many semantic options for error usage is functionally the same as having many error types, except worse.
Please go write C++ and then come back to us
1 reply →
They all convert seamlessly, and the enums make the branches explicit. Don't even need to check the documentation to find which errors supposedly exists like in Go with its errors.Is, errors.As, wrapping and what not.
An easy rule before you make a knowledge based choice is Thiserror for libraries, helping you create the standard library error types and Anyhow for applications, easy strings you bubble up.
Or just go with anyhow until you find a need for something else.
https://crates.io/crates/anyhow
https://crates.io/crates/thiserror
11 replies →
[dead]
Surely you need an alternative to Box<dyn Error> for reporting memory allocation failures?!
Anything other than panic/abort on allocation failure is outside the scope of the vast majority of programs, including anything using the standard library in Rust. I wouldn't worry about Box<dyn Error>.
A &(dyn Error + 'static) should be fine for that; you don't need any allocated/variable sized data in a memory allocation failure.
16 replies →
You're already writing Rust in a very different style if you're writing the type of code that gracefully handles allocation failure. It's to Rust's immense credit that this type of coding is actually fairly well-supported (unlike in Go), but you're already a bit off the beaten path for stuff like error handling.
Not sure what your problem is?
If you need to handle an allocation error in the error path, then the error reporting path must abort, which means that the allocation error must be bubbled up.
There is no real solution to an allocation error inside the error path. Even if you preallocate an arena for errors, the error might be large enough that it won't fit inside the arena.
Hence the best thing you can do from that point onwards is to have an error enum with an AllocError variant that doesn't allocate. Said error won't contain any information beyond line numbers of the allocation error since you just don't have the space for it.
In the end you will basically end up with panic free code, but the error still bubbles up like regular unwinding.
So yeah you can do it, and I will do it in the future, but I personally think that the people who think this is some huge deal breaker don't understand the problem in the first place.
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.
Go has the Green Tea GC since 1.25. It’s no longer simplistic and quite well engineered. The AVX-512 support was especially interesting to me.
https://go.dev/blog/greenteagc
I've run into GC pauses, I think in many (most?) cases there is some class of bulky data that you can either move into slices of pointer-free structs (so the GC doesn't scan them) or off-heap entirely. The workload where GC is slow is also likely prone to fragmentation so whatever the language you'll have to deal with it.
Java with its copying GC deals fine with fragmentation albeit at the cost of more upfront memory. And even in Rust one can change the allocator to try to deal with fragmentation. But with Go there is simply no good options besides the rewrite.
1 reply →
> For me the main advantage of Go over Rust is compilation speed.
Interestingly, Rust has quite good failed compilation speed. That's almost good enough. The usual Rust experience is that it's hard to get things to compile, and then they work the first time.
I've never been bothered by long compilation times, it gives me time to think about what the code should actually do.
To other people's usage patterns though, I imagine the group of people who don't do much with the type system rely more on running a built binary to see if it worked, which means they'll pay the full compile/link time cost more often.
Rust compilation speed is a matter of tooling, they could have something like OCaml or Haskell interpreters, which so far hasn't been a priority.
Or having Cranelift as default backend.
What kind of apps are you writing where GC spikes matter?
trading, networking, gaming, ai, realtime, almost anything with hard response requirements.
if you are hitting pauses due to GC issues, you should into putting appropriate data structures into a memory arena, here's a reasonable read:
https://uptrace.dev/blog/golang-memory-arena
These are all tools. Java used to have this all the time, and we (ex-java programmer) had ways around this until the JVM improved.
Isn’t it somewhat easy to remove allocations in Go? I haven’t had to “rewrite” as such, but rather lifting some allocation out of loop. Am I misunderstanding the scenario?
Pauses are a problem with heap size and structure, not allocation rate, because the pause is caused by GC code that is O(heap size). Making garbage slower reduces the frequency but not severity. This is an issue with most GCs to some degree, there are phases of collection where the GC stops execution and the duration is relative to how much work it has to do which is based on how many objects and how much memory needs to be checked. "Concurrent" garbage collection is the approach of trying to reduce the pauses by doing more of the work while program execution continues. It's complicated and hard to get right, so Go's original GC was IIRC fully stop-the-world.
There are some fine points to the O(heap size), for example it's clearly unnecessary for the GC to scan objects that do not themselves contain pointers, and work is somewhat proportional to the total number of objects. Combining numerous small objects into manually managed slices, coming up with ways to make the most numerous items pointer-free, etc.
I learned a bit about this when an analytics workload I had ended up with unacceptable pauses (I think over 1 second), Go's GC is more sophisticated now but I think in any GC runtime you have the same considerations to some degree. Some of the best writing at the time was by Gil Tene, one of the principal authors of the C4 concurrent collector at Azul Systems, starting point here:
https://groups.google.com/g/golang-dev/c/GvA0DaCI2BU/m/SmEel...
With backend serving many clients with widely varying performance profile of individual requests when latency spikes happen there is no particular hot loop. Just many go routines each doing reasonable thing but with a particular request pattern hitting pathological case of GC.
1 reply →
Removing enough allocations to avoid fragmentation can be maddenly difficult/tedious.
> Rust still rely on many C and C++ libraries
Yes but Rust has a lot more availability of libraries to do stuff as a result. Want to do anything ML or scientific? You at least have a route in Rust where you don’t with Go.
With Go basic stuff like url parsing or HTTPS support is written in Go and comes with the standard library. With Rust too many necessary things are just wrappers around C and C++ making cross-compilation and reproducible builds much harder to archive.
As for availability if CGO is ok, then calling C or C++ code from Go is not that hard. Also, there is always an option to just start C++ process if extra data copies are OK.
2 replies →
Has there been a lot of progress with ML in Rust? I don't really keep up with it because it seems like every crate ends up getting abandoned and I just gave up caring.
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).
Conversely, the Go community tends to actively shun frameworks, especially anything Rails-like, and will tell you to just use the standard library. Which is good advice, the standard library really does have everything you need. But it's also roughly on a par with what's available in Rust (though as someone said above, the Go stdlib routines have been heavily, massively, tested in production by now, and are fully mature and load-bearing).
Interesting! Are Go backend building custom auth, admin, DB ORM/migrations/auto migrations, templates, email, dev server etc for each project? Or each person and org has their own toolkit they use?
10 replies →
For backend web dev, there are advantages. I really like Axum's use of typing:
With a route like:
…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.
go is slightly more verbose (surprise) but you can achieve the same thing using struct binding in gin:
This is actually a great example - what happens in that Rust version when the input parsing fails? Go makes it explicit.
I'm not sure if that's a great example. What kind of errors could ShouldBindQuery return?
I would assume Axum returns a bad request error for you when query parsing fails, but if you do want more control over how the error is handled, you can change the parameter type to Result<Query<bool>, QueryRejection>, and the type system itself documents precisely what errors you can match against.[0]
[0]: https://docs.rs/axum/latest/axum/extract/rejection/enum.Quer...
[dead]
The Go standard library has learned to interpret path variables as well:
https://go.dev/blog/routing-enhancements
To be fair, it's not -quite- as useful - `req.PathValue` only returns `string` and you have to do the conversion to other types yourself which could lead to a faffy mess of code.
A project I work at uses a similar pattern (similar from what I can see):
It's just a wrapper.
It also serializes/deserializes responses and handles both JSON and templates.
db is just a singleton-lifetime dependency, we often also have ctx, http.Request, http.Response, Cookie, which are request-time lifetimes.
I thought about open-sourcing it but most Golang developers seem to hate it with a passion, so I just gave up, haha.
You can not use async right? Maybe not with axum but I imagine there are fully blocking frameworks for rust.
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.
He's not making that up; in practice, you're going to run into and need to make mental space for the idiosyncrasies of multiple error frameworks.
Not sure what you mean by that. If you're consuming the API of a crate that has functions that return errors, you're not really dealing with a "framework", you're just dealing with whatever the `E` is in the `Result<T, E>`. If that `E` doesn't implement std::error::Error, I'd consider that a deficiency (even a bug) for that crate. (Yes, I know some crates want to support use in `no_std` environments; that's what features are for.)
If I care about the specific variants of error that a function can return, so I can do different things depending on what kind of error occurred, I'll read the docs and match. That's not really a "framework" thing; that's just a basic thing that anyone has to do in any language in order to consume an API. If I need to propagate the error, I'll do so (either directly, or by wrapping it in a variant of my own error type). I don't see how any of this is "framework"-y.
A crate's decision to use thiserror (or not) does not matter to me. If a crate exposes `anyhow::Error`, that's a lazy choice and bad API design, but still "works" and I generally don't need to care about it.
Or is there something else you meant when you said "error frameworks"?
1 reply →
I guess you might have to if you need to use a library someone's written that doesn't implement the standard.
Writing primarily applications, I couldn't tell you what error handling frameworks my dependencies are using: I literally don't know, and haven't needed to know in order to display, fail, or succeed.
EDIT to add: I use anyhow for this, so I should also add "add context to an error when I fall" to the list of things I do.
9 replies →
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.
Standard library is something you have to maintain for all eternity, with identical API. It had been argued that some concurrency primitives like channels would have been better outside of std (for rust, to be clear). Once dependency management is solved, a small std is beneficial.
> you have to maintain for all eternity, with identical API
People always tout this as a huge reason for not wanting a too big std in Rust (or "too useful" either), but IMHO that's just talking about reaching theoretical optimals, while leaving the community for years without good guidance via providing a opinionated practical and pragmatic way of doing things. Which I find to be a very unhelpful stance for a tool such as a programming language.
If a design of some std package didn't pass the test of time, and a new iteration would be beneficial, the language can leave its original API version right there, and evolve with a v2, with an improved and better thought out API after learning from the mistakes of v1.
Prime example: "hey we found that math/rand had some flaws, so here is math/rand/v2". A practical solution, and zero dramas as a result of having rand be part of std.
1 reply →
I use go because of the large and useful stdlib. I rarely have to reach for an external library, and even then I only consider libraries that are very popular. If a library isn’t available, I’ll just write my own, using the stdlib. I recently used the awesome crypto library to implement an envelope encryption system, I didn’t need anything outside of the stdlib or Google’s x library (x is effectively the experimental stdlib).
Having too much external code, like npm or rust crates, seems like a nightmare for me.
Doesn't Rust already have that solved via editions? If anything, that's the language that's especially well positioned here.
2 replies →
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.
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.
Go funcs can return both a value and an error, or neither, it's a common gotcha. Having to check the behavior each time is no fun.
Missing error handling is checked at compile-time in Rust (lint-time in Go), and can be enabled for any struct or function (https://doc.rust-lang.org/reference/attributes/diagnostics.h...), not just `Result<T,E>`.
Returning an error to the caller in Rust can be done with a single character.
In Go you can ignore the error value though, and use directly the returned value (`int` in your example). In Rust you cannot do that, you need to unwrap the Result or use the `?`
If the returned value is still valid despite an error, then the function would return (u32, Option<Error>), perfectly valid rust. If the value is meaningless in case of an error then using it is incorrect code; you wouldn't want to do that in either language and rust makes that assumption explicit with unwrap. If you want a default value in case of error just use unwrap_or_default.
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.
What is "formal QA support"?
> 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!
The funny thing is: All Rust source code looks like an assembly syntax error.
If you spend an hour skimming the Rust Book it's not really that bad
It's not that bad, but when compared to C or Go, it's not something that I would like to type by hand. At least Java has IDEs which reduce the amount of verbosity you need to type. I know you get safety, but the verbosity and cargo is is a con in my opinion.
[flagged]
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.
Been playing with Lisette for a few weeks, so far im really liking it. Think is has some potential.
Rust is easily one of the worst languages to look at
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).
thiserror and anyhow are std::error::Error with fewer steps.
They're external crates that either generate Error implementations (thiserror) or act as dynamic wrappers implementing Error (anyhow), so they're more than a simple hand-written implementation. But the developer experience of pulling thiserror or anyhow off the shelf can certainly be more convenient than the hand-written implementation, sure.
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.
Or gleam if you don’t fancy elixir.
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.
>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.
[flagged]
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.
Linters are available to catch you before you compile - with Go
Generally speaking there has to be a mechanism for optional handling of return values, in Go you can ignore everything (ew), you can use placeholders `_`, or you can explicitly handle things - my preference.
If you say "Well in C you have to handle the returns - I am not across C enough to comment, but I will ask you - Does C actually force you, or does it allow you to say "ok I will put some variables in to catch the returns, but I will never actually use those variables" - because that's very much the same as Go with the placeholder approach
edit: I am told the following is possible in C
trySomething(); // Assumes that the author of trySomething has not annotated the function as a `nodiscard`
(void)trySomething(); // Casts the return(s) to void, telling the compiler to ignore the non-handling
int dummy = trySomething(); // assign to a variable that's never used again
I welcome correction
C, as a language, cannot bother less about you using or not using the return values, checking them, discarding them, or using them to index an array without any bounds checking. Various linters and compilers may have their opinions, expressed as warnings, but at the end of the day it's completely up to you as a developer.
3 replies →