It's interesting that you find Go to be Rust-adjacent. Setting aside the USPs of each language (goroutines and borrow checker respectively) and just speaking about the general experience of writing code, I find Go painful for all the reasons that I find Rust pleasant.
The best summary I can give of Rust is that it was designed by people who learned from the mistakes of the programming languages that came before it.
The best summary I can give of Go is to quote Rob Pike's response [0] to a request for syntax highlighting in the Go playground:
> Syntax highlighting is juvenile. When I was a child, I was taught
arithmetic using colored rods
(http://en.wikipedia.org/wiki/Cuisenaire_rods). I grew up and today I
use monochromatic numerals.
It's like my favorite John Quincy Adams quote, "It is what it is, and it ain't what it ain't" Different strokes for different folks you know? At the end of the day if folks code at all, and it makes them happy, that's a good thing.
It is mostly an example of the mindset that I think GP is trying to illustrate.
Go has nil where Rust has Option.
Go has weird not-quite-tuple returns & if err != nil where Rust has Result.
Go has no real enum concept, where rust has its powerful enums and matching constructs.
Go has generics, but only after a decade of pressure from users (and even then, they are much much less useful than Rust's type system).
I like Go and I feel very productive in it, but its commitment to simplicity is dogmatic in many ways and it very much is missing milestone advancements in PLs from the past several decades. It could easily have been made in the 90s.
I would love a language that combined the best aspects of Go and F#: expressive, great type system, fast compilation, native binaries, opinionated formatter, excellent concurrency, comprehensive standard library, consistent documentation, etc.
Throw in great compile to JS capabilities with small bundle sizes and the ability to map Typescript typings into the language so you can seamlessly consume well typed libraries, and man. Killer language, right there.
I feel like Go was built with primary design considerations that are often not considered publicly and often at odds with what programmers want out of a language. I saw one of the first public talks from the creators at Google I/O and they stressed two things: compilation speed and new developers coming up to speed quickly. From what they said, Google had a few C++ projects with multi-hour compilation times that, when profiled, showed about 90% of the time was spent reading header files. So a core Go philosophy was single-pass compilation to cut down compile times as much as possible. Similarly they stressed that the focus on simplicity meant there wasn’t as much variation in style of Go code and new programmers—even those unfamiliar with Go—could quickly come up to speed and contribute to a project.
Viewed through this lens, the resistance on the part of the creators to changes that compromise these values even a little bit makes sense. Generics take time to get used to and any code base that makes extensive use of them will take longer to get up to speed in, even if it enables you to move faster later on.
That talk has really shaped how I look at Go. I think it solves problems that Google has (really large projects built by teams that have a ton of turnover) really well. But as with a lot of things that emerge from Google, it’s a solution to a problem that not too many other companies face. The ones that do will get an awesome tool that’s proven to work. But the ones for whom it’s 90% of what they need are going to get a lot of pushback getting that last 10% accepted because it already does almost exactly what Google needs it to do and any departure from that will be, in their minds, counterproductive.
I agree, I've mostly made peace with what Go is and I still enjoy using it.
It just tantalizes me because of how close it is to my ideal general-purpose programming language. There is a large middle ground between the minutes-long compile times of Rust and the seconds-long compile times of Go.
It doesn't, primarily the way I saw the discussion heading was (warning: strawmen ahead):
> "Go is a good alternative to Rust because it is easy to write performant, concurrent code"
> "Go is not very comparable to Rust. I won't describe why, here's a quote by Rob Pike and I'll strongly imply it's because its creators deliberately avoided complexity, even where useful."
> "You did not explicitly criticize anything about Go, therefore it must not have flaws"
Then I came in and described exactly where I feel Go ignores the state of the art in PLs.
> But what does any of that have to do with (Rust-shaped vomit)
Go doesn't need all those type system gymnastics because it does not have the problem of the borrow checker to deal with and doesn't promise to avoid segfaults for you.
It is a serialization of relative lifetimes, basically. Whenever you write code in any language that doesn't have a GC, you either have to maintain a mental map like this to avoid bugs, or you make the language do it for you like Rust does.
Yeah I don't mean to criticize Go's generics for being less featureful given how late they were introduced, but they do currently prevent me from building any kind of mapping/filtering/pipeline style code because of their limitations (no generic type parameters on methods). A Go implementation of Result or Option could paper over the lack of sum types if we only had that.
The more I think about it, what I really want is something with the ML feeling of Rust, but in the space that Go occupies (good performance GC languages). Go frustrates me because it nails the runtime and tooling side of things but falls far short of it in the other ways I mentioned.
There's no shortage of good-perf languages with a GC: F# would be one prominent example that sounds very similar to what you describe.
The usual objection is that it requires a .NET runtime, whereas Go produces a single self-contained executable. But .NET can produce self-contained executables these days.
Yes, .NET can produce binary executables, but is it a common practice? I’m asking because I think the ecosystem matters a lot. If it’s a common practice, then it’s more tested and more stable and you get more tools and documentation.
It's a relatively recent feature, at least the "pure" implementation (what they had before was, essentially, a self-extracting binary), so it's still gaining popularity. But seems to be fairly common with containers.
As the sibling commentor said, syntax highlighting is only one example meant to illustrate Go's sometimes unnecessarily frustrating design. In case it wasn't clear, the example wasn't that Rob Pike doesn't like syntax highlighting. The example was that Go's playground doesn't have syntax highlighting (even as an option) for a reason as arbitrary as "because I said so".
That is why I find Rust and Go to be dissimilar. Rust is a language full of good ideas, almost all of which didn't originate in Rust. Go feels like it was designed with a very specific brief - "we want C but with GC and easy concurrency" - but whose designers otherwise had an NIH syndrome-like aversion to good ideas and common sense.
I don't agree with your framing. You are stating a 'moral' proposition, i.e. Rust == Good Ideas AND Go == Bad Ideas, and then applying the 'moral' position to the language as a whole. So you end up saying, in brief (and acknowledging that I do not think you are actually making a moral claim about the qualities of these languages) you are saying Rust is Good, Go is Bad and therefore they are dissimilar. I don't think the reasoning your putting forward actually says anything about the language and there similarity/dissimilarity.
I am not saying that Go and Rust are similar or not. I don't really agree with GP's comment where Go should be in the running for a Rust-with-GC/slightly-higher-level-Rust, but the frankly dismissive Rust Good therefore not similar to Go Bad is not justified. Although the conclusion regarding similarity is probably correct.
Also, this is a little off topic, but I have seen multiple people say that Go 'was designed with a very specific brief - "we want C but with GC and easy concurrency"' and then go on to complain about the lack of things like generics, destructuring match syntax, functional concepts, etc. But, all of those discussion, including your comment, start out with what seems to be an acknowledgement that Go's design had a very specific target. I agree that Go is basically the fulfillment of the brief you gave, i.e. C with GC and easy concurrency. So, when the target is C with two unique things, why does everyone then seem confused that Go doesn't have all of these extra 'good ideas and common sense'.
I'm not trying to turn this into a thread on Go's merits or lack thereof. I just don't understand why so many people seem to think that Go somehow didn't do exactly what it set out to do. You don't have to think what they decided to design was a worthwhile language, but to expect a lion to be a shark, or an apple be a steak, is just illogical.
I appreciate your comment. My intention wasn't "Go is dissimilar because it's bad and Rust is good" but I can see why you'd think that. I'll attempt to clarify.
The reason I like and recommend Rust is the number of decisions it gets right which are completely orthogonal to the borrow checker. It's clear that a lot of thought was put into the unexciting parts of the language. That's why I like using it even though I don't particularly need the borrow checker and I'd be happy with GC. Some examples off the top of my head:
- Expression-oriented nature makes code easy to write and nice to read
- Compilation errors are as clear and helpful as possible
- Comprehensive yet skimmable API documentation
In short, Rust is a nice language outside of the borrow checker.
A lot of the things which strike me as nice about Rust can't be said about Go.
For that reason I think Go is a surprising suggestion for someone who likes Rust but doesn't care about ownership and lifetimes.
There are a number of minor but valid frustrations I encounter when writing Go which are completely orthogonal to the brief of "C but with GC and easy concurrency". I'd understand if these problems were a result of the language's goals but often they seem to exist for no particular reason. In that regard I think Go is quite dissimilar to Rust.
You’re comment make your point very well. Honestly, so did the first comment. Sometimes I find myself so tired of just lurking and reading HN that I just text dump some comment onto a totally valid parent comment.
I like Go a lot. At my previous employer a lot of the systems we wrote for log processing were written in Golang. And I thought it was really nice; I can compile my code really quickly and code in general will run pretty fast. I've only used in the space of big data file processing though.
My only real issue with Go is that I feel the language part itself is simplistic and doesn't have the kind of type/trait/typeclass/similarthing like Rust or Haskell has. In Haskell I especially like doing DSLs using monads, e.g. I did a integer-problem-to-SAT-problem DSL and another DSL for NetHack playing AI. In Go making these DSLs is more pain. Although I think that would be true for Rust as well, just not as much.
Hare is not rust adjacent, sorry. It can't even represent the (small) stdlib of rust since it lacks generics, RAII... Not to mention the memory safety. It belongs in a different class of languages.
Go's lack of expressivity and weak as hell type system is hardly close to Rust, like I can barely see a similarity other than both being a PL. Hell, probably Java is closer to Rust than Go, at least it is also nominally typed.
Just wacky I had to scroll this far to see Go mentioned. In certain contexts Rust is very impressive, in others Go is a much better choice. I'm really starting to hope that we'll see some of the important advancements in Rust packaged up in a better language.
These one-liners aren't super-constructive, my own comment was hardly in-depth, so whatever...
On any team or in a community your most likely to have a range of skill levels across members. A language can be many things, a powerful tool or a strong barrier.
When I first heard about Rust I thought we were on the verge of getting some real advancements across a much larger community of developers and scope of projects. Instead I think we're headed further down a path of at least 3 major groups of PL (scripting, memory-managed, precise semantics). Who knows, maybe it's for the best. If so we better get busy improving the inter-op.