Earlier quoted context omitted.
You can just as easily add context to the first example or skip the wrapping in the second.
Especially since the second example only gives you a stringly-typed error. If you want to add 'proper' error types, wrapping them is just as difficult in Go and Rust (needing to implement `Error` in Go or `std::Error` in Rust). And, while we can argue about macro magic all day, the `thiserror` crate makes said boilerplate a non-issue and allows you to properly propagate strongly-typed errors with context when needed…
Thoughts on Go vs. Rust vs. Zig
531–540 of 599 posts
Re: Thoughts on Go vs. Rust vs. Zig
#532Earlier quoted context omitted.
I'm in a similar place, but my stack is Python->Go With Python I can easily iterate on solutions, observe them as they change, use the REPL to debug things and in general just write bad code just to get it working. I do try to add type annotations etc and not go full "yolo Javascript everything is an object" -style :) But in the end running Python code on someone else's computer is a pain in the ass, so when I'm done…
I'm in the camp of "If your target is Go, then prototype in Go." I don't bother with the intermediate step. Go is already so very close to being a dynamic language that I don't get the point. Just write "bad" Go to prototype quickly. Skip the error checks. Panic for fun. Write long functions. Make giant structs. Don't worry about memory. You mentioned running someone else's python is painful, and it most certainly is…
With Rust, it was amazing - it was a pain to get it compiled and get past the restrictions (coming from a Python coder) - the code just ran without a hitch, and it was fast, never even tried to optimize it.
As a Python 'old-timer' , I also am not impressed with all the gratuitous fake typing , and especially Pydantic. Pydantic feels so un-pythonic, they're trying to make it like Go or Rust, but its falling flat, at least for me.
Re: Thoughts on Go vs. Rust vs. Zig
#533You can write your own allocator in C. You don't have to use malloc.
Re: Thoughts on Go vs. Rust vs. Zig
#534Earlier quoted context omitted.
So, one year ago? After more than 25 years without it? And a lot of people writing Java can't update to that.
Yeah, FFM adds many quality-of-life features - scoped lifetimes being a standout. If you just want an arena interface, ByteBuffer has been there since Java 1.4 (2002). It also does off-heap w/ ByteBuffer.allocateDirect(). https://docs.oracle.com/en/java/javase/25/docs/api/java.base...
Re: Thoughts on Go vs. Rust vs. Zig
#535Earlier quoted context omitted.
I disagree, adding context to errors provide exactly what is needed to debug the issue. If you don't have enough context it's your fault, and context will contain more useful info than a stack trace (like the user id which triggered the issue, or whatever is needed). Stack traces are reserved for crashes where you didn't handle the issue properly, so you get technical info of what broke and where, but no info on what…
It's one piece of information, but logging at the error location does that still. And if you have a function that's called in multiple places how do you know the path that got you into that place. If it wasn't useful we wouldn't try to recreate them with wrapped errors
You can get away with not doing that when cowboy coding scripts. Python was designed to be a scripting language, so it is understandable that in Python you don't often need to worry about it. But Go isn't a scripting language. It was quite explicitly created to be a systems language. Scripts and systems are very different types of software with very different needs and requirements. If you are stuck thinking in terms of what is appropriate for scripting, you're straight up not participating in the same thread.
Re: Thoughts on Go vs. Rust vs. Zig
#536Earlier quoted context omitted.
Especially since the second example only gives you a stringly-typed error. If you want to add 'proper' error types, wrapping them is just as difficult in Go and Rust (needing to implement `Error` in Go or `std::Error` in Rust). And, while we can argue about macro magic all day, the `thiserror` crate makes said boilerplate a non-issue and allows you to properly propagate strongly-typed errors with context when needed…
fmt.Errorf with %w directive in fact wraps an error. It will return an fmt.wrapError struct which can be inspected using `errors.Is`. So it's not stringly typed anymore.
In practice, this ends up with several issues (and I'm just as guilty of doing a bunch of them when I'm writing code not intended for public consumption, to be completely fair).
fmt.Errorf is stupid easy to use. There's a lot of Go code out there that just doesn't use anything else, and we really want to make sure we wrap errors to provide 'context' since there's no backtraces in errors (and nobody wants to force consuming code to pay that runtime cost for every error, given there's no standard way to indicate you want it).
errors.New can be used to create very basic errors, but since it gives you a single instance of a struct implementing `error` there's not a lot you can do with it.
The signature of a function only indicates that it returns `error`, we have to rely on the docs to tell users what specific errors they should expect. Now, to be fair, this is an issue for languages that use exception's - checked exceptions in Java notwithstanding.
Adding a new error type that should be handled means that consumers need to pay attention to the API docs and/or changelog. The compiler, linters, etc don't do anything to help you.
All of this culminates to an infuriating, inconsistent experience with error handling.
Re: Thoughts on Go vs. Rust vs. Zig
#537Earlier quoted context omitted.
Compared to what? Because compared to go which has not one but 2 nulls, and an even more anemic type system it is surely much better. > the type system definitely doesn’t help you write correct programs. It surely helps significantly. You are just looking for even more from the type system, but that's another (fair) statement to make.
I started this thread criticizing Go. I think it’s a terribly verbose language that has ignored all language dev of the last half century. It’s why I continue to write Java. However, I don’t think that shields Java from its inability to make the language better. We still don’t have checked nulls and at this rate, even though there’s a draft JEP, I am not sure we will get them within this decade. The community still b…
As for unchecked exceptions, that may be a bit of an "unreasonable ask". The only language that properly solves the problem are languages with effect types, which are an active research area. Every other language have either FP-like error values, or just unchecked exceptions (and there are terrible "solutions" like errno and whatever go does), or most likely both. E.g. Haskell will also throw exceptions, not everything is encoded as a value.
In my opinion both is the most reasonable approach, when you expect an error case, encode it as the return type (e.g. parsing an Integer is expected to fail). But system failures should not go there, exceptions solve it better (stuff like the million kind of connection/file system issues).
Re: Thoughts on Go vs. Rust vs. Zig
#538Earlier quoted context omitted.
> But you only need about 5% of the concepts in that comment to be productive in Rust. The similar argument against C++ is applicable here: another programmer may be using 10% (or a different 5%) of the concepts. You will have to learn that fraction when working with him/her. This may also happen when you read the source code of some random projects. C programmers seldom have this problem. Complexity matters.
A similar problem applies to Go, just inverted. Take iteration. The vast majority of use cases for iterating over containers are map, filter, reduce. Go doesn't have these functions. That's very simple! All Go developers are aligned here: just use a for loop. There's no room for "10% of concepts corners", there's just that 1 corner. But, for loops get tedious. So people will make helper functions. Generic ones today,…
Re: Thoughts on Go vs. Rust vs. Zig
#539Earlier quoted context omitted.
> It's exceedingly rare to see any sort of global mutable state I know a bit of Rust, so you don't need to explain in details. How to use a local cache or db connection pool in Rust (both of them, IMO, are the right use case of global mutable state)?
Why does that have to be global? You can still pass it around. If you don't want to clobber registers, you can still put it in a struct. I don't imagine you are trying to avoid the overhead of dereferencing a pointer.
Re: Thoughts on Go vs. Rust vs. Zig
#540Earlier quoted context omitted.
I’m not sure there’s anything clever that resolved the issues, they just settled on slow execution times by accepting a dynamic dispatch on generics.
Not according to this post: > Go generics combines concepts from "monomorphisation" (stenciling) and "boxing" (dynamic dispatch) and is implemented using GCshape stenciling and dictionaries. This allows Go to have fast compile times and smaller binaries while having generics. https://deepsource.com/blog/go-1-18-generics-implementation