In addition to what the other post said, Go also favors simplicity for the programmer. So stack and heap are "unified", a lot of dispatch is virtual and you rely on the compiler optimizing away all the dynamisms and checks. As you might imagine, the compiler has been getting better, but these are hard problems.
If you are willing to spend time on it, you can improve Go's performance quite a lot by finding places where heap escape analysis failed, and trying to fix them. But this is extremely frustrating to do.
Another thing is interfaces and all the runtime checks Go likes to do. In C++ parlance, every interface-valued dispatch is virtual by default.
For many, Go is "fast enough". Usually it's within a factor of 2 of Rust, which puts it far ahead of the interpreted languages it's usually replacing.
I used to say this too, but after I've been writing Rust for a few years, in hindsight it feels like Go as a language is simpler, but I tend to end up with more code to maintain.
I guess the error handling leaves a bit to be desired for, and I'd say even though it's better than exceptions, I still prefer Result in Rust.
I hope that with the introduction of generics in Go, things will become simpler (I know a lot of people dislike this type of polymorphism because it feels like extra complexity, but I've always seen it as a tool to reduce complexity)
I think the amount of code you need to maintain and simplicity are orthogonal things. When we say go is simple, what we usually mean is that by looking at a bit of code, it's obvious what it does. There's no way that `x + y` can be anything other than addition, or `f(x)` anything other than a function call. It also means, that only function calls can hide additional complexity. You could also talk about lexical proximity to things that can affect the outcomes.
By that metric, Rust is complex. Looking at a piece of code, it could do basically anything at all. It can get rewritten by a macro, operators can be overloaded, any line of code can hide implicit magic that you have no way of knowing about.
Rust gets away with being complex by having lots of correctness checks. C++ is about as complex as Rust, but, without the correctness checks, it can be a nightmare. In Rust, it might be hard to tell what happens when you run some code, but at least you know it will be nothing terrible.
what does simple mean?
1) Simple for me, writing the code
2) Simple for you, reading the code
3) Simple for the SREs who have to operate the code
4) Simple in the sense that there aren't many abstractions
5) Easy to refactor
6) Easy to use and test (a function is simpler than a bunch of objects)
7) Simple to debug (no state is simpler than yes state)
Both Go and Rust score pretty high in aggregate on these different definitions of simple, but they get there in very different ways.
* writing # Go > Rust
* reading # Rust > Go
* operate # Go = Rust
* abstraction count # Go >> Rust
# refactoring # Rust >> Go
# testing # Rust > Go
# debugging # Rust >> Go
Obviously these are my own opinions, yours may differ.
The underlying theme here for me: Go is somewhat easier to write right out of the gate but significantly worse to maintain. Once Rust is written it is bulletproof. Refactoring is trivial to a degree that's hard to believe if you haven't done it.
Since code is read and maintained significantly more often than it's written… you can probably guess where I end up.
Go’s error handling is definitely not better than exceptions, not even close. It is just “errno” from C with bad syntax sugar.
Exceptions don’t disappear randomly (no, an ‘if err’ is not error handling, and repetition just makes it prone to bugs) and they contain a stacktrace. You don’t have to grep for error messages like some caveman. It even lets you live in some Schrödinger error state where both a value and an error was returned.
I have sympathy for your position, but you don't even need exceptions.
Go uses a tuple for error handling. As you say the compiler can't help you avoid Schrödinger's errors. If Go instead had used something like Rust's `Result` and had given you the tools necessary for dealing with generics, then most of your objections would go away.
If you are willing to spend time on it, you can improve Go's performance quite a lot by finding places where heap escape analysis failed, and trying to fix them. But this is extremely frustrating to do.
Another thing is interfaces and all the runtime checks Go likes to do. In C++ parlance, every interface-valued dispatch is virtual by default.
For many, Go is "fast enough". Usually it's within a factor of 2 of Rust, which puts it far ahead of the interpreted languages it's usually replacing.
reply