Live data from Hacker News

Thoughts on Go vs. Rust vs. Zig

sinclairtarget.com

91–100 of 599 posts

Re: Thoughts on Go vs. Rust vs. Zig

#91

Generally a good writeup, but the article seems a bit confused about undefined behavior. > What is the dreaded UB? I think the best way to understand it is to remember that, for any running program, there are FATES WORSE THAN DEATH. If something goes wrong in your program, immediate termination is great actually! This has nothing to do with UB. UB is what it says on the tin, it's something for which no definition is…

I think it's common to be taught that UB is very bad when you're new, partly to simplify your debugging experience, partly to help you understand and mentally demarcate the boundaries of what the language allows and doesn't allow, and partly because there are many Standards-Purists who genuinely avoid UB. But from my own experience, UB just means "consult your compiler to see what it does here because this question i…

> But from my own experience, UB just means "consult your compiler to see what it does here because this question is beyond our pay grade."

People are taught it’s very bad because otherwise they do exactly this, which is the problem. What does your compiler do here may change from invocation to invocation, due to seemingly unrelated flags, small perturbations in unrelated code, or many other things. This approach encourages accepting UB in your program. Code that invokes UB is incorrect, full stop.

Re: Thoughts on Go vs. Rust vs. Zig

#92

I love this take - partly because I agree with it - but mostly because I think that this is the right way to compare PLs (and to present the results). It is honest in the way it ascribes strengths and weaknesses, helping to guide, refine, justify the choice of language outside of job pressures. I am sad that it does not mention Raku ( https://raku.org ) ... because in my mind there is a kind of continuum: C - Zig - C…

what's WL?

Re: Thoughts on Go vs. Rust vs. Zig

#93

The reason I really like Zig is because there's finally a language that makes it easy to gracefully handle memory exhaustion at the application level. No more praying that your program isn't unceremoniously killed just for asking for more memory - all allocations are assumed fallible and failures must be handled explicitly. Stack space is not treated like magic - the compiler can reason about its maximum size by exam…

> No more praying that your program isn't unceremoniously killed just for asking for more memory - all allocations are assumed fallible and failures must be handled explicitly.

But for operating systems with overcommit, including Linux, you won't ever see the act of allocation fail, which is the whole point. All the language-level ceremony in the world won't save you.

Re: Thoughts on Go vs. Rust vs. Zig

#94
post #29

> In Rust, creating a mutable global variable is so hard that there are long forum discussions on how to do it. In Zig, you can just create one, no problem. Well, no, creating a mutable global variable is trivial in Rust, it just requires either `unsafe` or using a smart pointer that provides synchronization. That's because Rust programs are re-entrant by default, because Rust provides compile-time thread-safety. If…

so does the rust compiler check for race conditions between threads at compile time? if so then i can see the allure of rust over c, some of those sync issues are devilish. and what about situations where you might have two variables closely related that need to be locked as a pair whenever accessed.

In rust, there are two kinds of references, exclusive (&mut) and shared(&). Rustc guarantees you that if you provide an exclusive reference, no other thread will have that. If your thread has an exclusive reference, then it can mutate the contents of the memory. Rustc also guarantees that you won't end up with a dropped reference inside of your threads, so you will always have allocated memory.

Because rust guarantees you won't have multiple exclusive (and thus mutable refs), you won't have a specific class of race conditions.

Sometimes however, these programs are very strict, and you need to relax these guarantees. To handle those cases, there are structures that can give you the same shared/exclusive references and borrowing rules (ie single exclusive, many shared refs) but at runtime. Meaning that you have an object, which you can reference (borrow) in multiple locations, however, if you have an active shared reference, you can't get an exclusive reference as the program will (by design) panic, and if you have an active exclusive reference, you can't get any more references.

This however isn't sufficient for multithreaded applications. That is sufficient when you have lots of pieces of memory referencing the same object in a single thread. For multi-threaded programs, we have RwLocks.

https://doc.rust-lang.org/std/cell/index.html

Re: Thoughts on Go vs. Rust vs. Zig

#95
post #63

Earlier quoted context omitted.

I feel like this misses the biggest advantage of Result in rust. You must do something with it. Even if you want to ignore the error with unwrap() what you're really saying is "panic on errors". But in go you can just _err and never touch it. Also while not part of std::Result you can use things like anyhow or error_context to add context before returning if theres an error.

Any sane Go team will be running errcheck, so I think this is a moot point.

I think it’s still worth pointing out that one language includes it as a feature and the other requires additional tooling.

Re: Thoughts on Go vs. Rust vs. Zig

#96

> Other features common in modern languages, like tagged unions or syntactic sugar for error-handling, have not been added to Go. > It seems the Go development team has a high bar for adding features to the language. The end result is a language that forces you to write a lot of boilerplate code to implement logic that could be more succinctly expressed in another language. Being able to implement logic more succinct…

Python's f = open('foo.txt', 'w') is even more succinct, and the exception thrown on failure will not only contain the reason, but the filename and the whole backtrace to the line where the error occurred.

> the exception thrown on failure will not only contain the reason, but the filename and the whole backtrace to the line where the error occurred.

... with no other context whatsoever, so you can't glean any information about the call stack that led to the exception.

Exceptions are really a whole different kettle of fish (and in my opinion are just strictly worse than even the worst errors-as-values implementations).

Re: Thoughts on Go vs. Rust vs. Zig

#97
post #69

Earlier quoted context omitted.

yeah but which is faster and easier for a person to look at and understand. Go's intentionally verbose so that more complicated things are easier to understand.

let mut file = File::create("foo.txt").context("failed to create file")?; Of all the things I find hard to understand in Rust, this isn't one of them.

Important to note that .context() is something from `anyhow`, not part of the stdlib.

Re: Thoughts on Go vs. Rust vs. Zig

#98

The reason I really like Zig is because there's finally a language that makes it easy to gracefully handle memory exhaustion at the application level. No more praying that your program isn't unceremoniously killed just for asking for more memory - all allocations are assumed fallible and failures must be handled explicitly. Stack space is not treated like magic - the compiler can reason about its maximum size by exam…

If you are pre-allocating Rust would handle that decently as well right?

Certainly I agree that allocations in your dependencies (including std) are more annoying in Rust since it uses panics for OOM.

The no-std set of crates is all setup to support embedded development.

Re: Thoughts on Go vs. Rust vs. Zig

#99
post #4

For a lot of stuff what I really want is golang but with better generics and result/error/enum handling like rust.

I cautiously agree, with the caveat that while I thought I would really like Rust's error handling, it has been painful in practice. I'm sure I'm holding it wrong, but so far I have tried: * thiserror: I spend ridiculous and unpredictable amounts of time debugging macro expansions * manually implementing `Error`, `From`, etc traits: I spend ridiculous though predictable amounts of time implementing traits (maybe LLMs…

I personally like the flexibility it provides. You can go from very granular with an error type per function and an enum variant per error case, or very coarse with an error type for a whole module that holds a string. Use thiserror to make error types in libraries, and anyhow in programs to handle them.

Re: Thoughts on Go vs. Rust vs. Zig

#100

Earlier quoted context omitted.

You can just as easily add context to the first example or skip the wrapping in the second.

I don't agree. There isn't a standard convention for wrapping errors in Rust, like there is in Go with fmt.Errorf -- largely because ? is so widely-used (precisely because it is so easy to reach for). The proof is in the pudding, though. In my experience, working across Go codebases in open source and in multiple closed-source organizations, errors are nearly universally wrapped and handled appropriately. The same is…

I think the standard convention if you just want a stringly-typed error like Go is anyhow?

And maybe not quite as standard, but thiserror if you don’t want a stringly-typed error?

Post reply on HN