EDIT: In fairness, there is one thing and exactly one thing I miss about Go: compile times. Rust is simply no competition here, but in trade, it is doing a ton of extra work. Trade offs.
I have written both languages professionally in various contexts for years. In point of fact, I've been writing Rust since before Rust 1.0 came out, although I didn't get my first Rust job until about 3 years later. They're both excellent languages. I actually didn't learn Go until several years after learning Rust, and at the time I didn't appreciate it like I should have, since I was so excited about Rust. Only after getting professional experience with Rust did I truly begin to appreciate how nice Go is for the things it is good at.
Go is just so much better suited for network-connected services (including but not limited to web backends), and Rust is better suited for batch processing or embedded contexts where no compromise on performance can be made, in my experience. There are lots of reasons for this, but it's off topic from the question, and the answer to the question is that I absolutely do go back to Go. Neither language is a perfect tool for all problems, and I constantly dream about building my own language that learns from the best of both... there is certainly room for improvement on both ends.
You can compare its domain (to a certain degree) to Java or C#, in which case the latter two are superior due to the reasons mentioned previously (enums, pattern matching, etc.).
I don't want to take sides, I want to enjoy programming and learning, that's all. When zealots zeal, kinder people either leave or go underground.
But sure, one is a low level language which can and thus must care about every little detail, while the other is a managed language. (And honestly, mixing the two as if they share the same niche is very off putting)
I you were to learn Rust from scratch, what project would you recommend for the "changing and breaking" approach?
But along the whole "break it" idea... I don't know if you're an IDE person or a text editor die-hard, but I've found that rust-analyzer helps a ton. I'm historically a "vim with no plugins" kind of guy, but I'm using VS: Code with the vim keybindings now, and even if I'm not changing some code and getting feedback from the compiler itself, using rust-analyzer to go "hey what's this type here? Where's it defined, let's go take a look" has helped a ton.
That said, types help and poking around helps, but it's not always a panacea. Today I'm working on fixing something that doesn't quite work, even though yesterday I figured out how to assemble everything I'm supposed to need from this library I'm using. "It compiles it works" is a thing people say, and while I feel that way often, it's not true all of the time, of course.
If you have never used C++ and your baseline is Go or JavaScript then it probably looks like a confusing hellscape. You have to learn a whole new kind of type system, a new nomenclature (“Vec”s instead of “Array”s), new concepts like allocators, plus the borrow checker and lifetime annotations, and module/crate system. Former C++ programmers only have to learn the latter half.
Obviously you didn't mean that as a universal rule, but for posterity, I'm a counter-example to that. I learned Rust before learning C++ or Go. If anything, I think this biased me _more_ towards Rust than the others; C++ just kind of felt like a more error-prone, less ergonomic Rust, and Go just felt like it took far too much boilerplate to get anything done.
I'm not sure this is accurate - have you seen modern TypeScript? I actually find that more confusing than Rust to read.
(FWIW, I was predominantly Python/JS-centric before just going "all in" on Rust. It's not that bad, in my experience - if anything, I find Rust "just works" whereas I got tired of the churn in those environments)
Rust and C++ are like Hebrew and Arabic. Difficult languages for an outsider, but if you speak one you have a significant head start towards learning the other. TypeScript is Japanese: knowing Japanese doesn’t help you speak Arabic, despite both being difficult.
On the other hand Golang can be fun in like a week of learning it.
Meanwhile Go doesn't even have algebraic data types. I can't imagine working with a language that doesn't have these kinds of functional features anymore after having gotten used to them.
That’s because Go does not have async code. It has sync code on an async runtime. Like e.g. Erlang/Elixir.
This is subjective - I for example have no real issues reading Rust code, but find Go to look like utter spaghetti on the screen.
No part of my comment was doing this, and this bit is entirely unnecessary and adds nothing to the comment you wrote except fan religious wars about languages.
I think my comfort with Rust moreso comes from it feeling like any other C-ish language in appearance. It reads as expected to me.
Rust requires designing the memory management (ownership/lifetimes) of a program, which Golang doesn't, so even if/when the cognitive load is (hypothetically) equal, there's an additional, non-trivial demand. This is not something that everybody wants in a project (the given tradeoff may not be worth); for sure, if I had to introduce a language in my team only for tooling purposes (ie. small programs), Rust would not be the most productive choice IMO.
But it's not easy to quickly prototype stuff with. Just recently I had to write no less than 7 small prototypes and I gave up on the second one, relearned Golang -- took me an hour -- and finished 3 prototypes in a day.
I tend to go all the way in languages so I can use them freely afterwards. But... In Rust's case I just can't justify the effort. Golang really helps you start off a project faster.
I'll still 100% Rust. I'm working on it every day. But indeed, let's use languages where they are at their best.
I have had year+ long breaks between writing Rust applications. I have been able to get back into it without issue very quickly. At least one of those times I successfully completed a large, sweeping refactoring of a project of mine that had lay untouched for three years. I can confidently say it would have been extremely difficult to do that same task in other languages I consider myself very proficient in and use daily.
This is basically the "Anyone who doesn't love my favorite movie hasn't watched it enough times" argument. Programming language design is a complex space, there are no "correct" opinions.
I wished Go formatter would compress
if err {
return err
}
to if err { return err }
Even better would be to extend the syntax to allow if err return err
But I am Ok with braces.There are two reasons to have match: exhaustiveness and destructuring/pattern matching. I don't think there's an if/else parallel to `match result { Ok(t) => { ... }, Err(e) => { ... } }`
The fact that a `nil` value can be made useful (which, AFAICT, means it won't blow up your program?) is not a good enough reason to include them in the language. Rust can do perfectly useful things with, say, `Option<Vec<T>>`, and it's possible to distinguish between `Some(vec![])` and `None`. If you care to ignore that distinction you're free to do `maybe_vec.map(|v| v.len()).unwrap_or_default()`. But IMO it's much better to tell the compiler to unify different cases (`None` and `Some(empty)`) than to have to work around the compiler's unification of those cases when you don't want it. It's always easier to increase entropy than to decrease it. (P.S.: should the sum of a nil list be 0, or NaN, or...?)
But if you look at e.g. Kotlin, or C# with "#nullable enable", it tracks whether a given reference can be null or not. So you write if-else code instead of match, but you have to do that in order to actually do something with a reference.
"Nil is useful", in Go, means that for expensive objects it's often appropriate to pass nil instead of an empty or defaulted object, and call methods on it that act as if it was an empty object or with some default/no-op behavior. This is most obvious with lists/maps but can be applied to all concrete types.
While I can imagine a language in which `Option<T>` can re-export some of `T`'s method set with a default behavior, in practice I don't know any which actually do this.
In Rust you write this type of thing as:
if let Some(name) = order.get_name() {
println!("Order ready for {name}!");
} else {
println!("Order number {} ready!", order.num());
}
So, it's a destructuring pattern match just written as an if-else. Because we did the match here, we can't forget and end up using name when there wasn't one, the variable only exists when it's bound.The other is most UIs are wrappers around other functionality, often in libraries. Working on anything other than pure Go code bases adds additional friction, and dynamic libraries add to that complication considerably.
I believe Go could be a really great fit for UIs, but likely never will be as there is little economic incentive to put in the incredible heavy lifting required to build up the support libraries. There are certainly some small projects trying, but without massive resources backing it, it is a struggle to achieve the full fit and finish that we've come to expect.
I appreciate it's error handling. It's burdensome, sure, but it presents almost no additional cognitive load when attempting to reason about control flow.
It essentially has no enums. However, it has a comfortable type system that can wrap primitive types, and you can define methods on those wrapped types. It's serviceable, but not elegant.
I have never been a fan of pattern matching outside of functional languages. The phenomenon I notice in languages that do have it, is the majority of uses cases seem to be a pattern match with two outcomes, one a Some() and the other a None(). It really seems like a more annoying way to write if {} else {}.
It has for, but it also has 'range.' It makes up for a lot.
It has nil pointers, which are just a "zero value." It's not uncommon to make it useful and safer in certain contexts. You can request a lookup in a map that is nil. You can ask for the length of a slice that is nil. You get sensible answers still. There are still footguns, but they're all single barrel.. which is _nicer_.
I don't need a perfect language. Good enough with low cognitive load and amazing cross-compile facilities I'll take any day of the week.