This is pretty cool. 50 million lines of code is quite a large corpus to work off of.
I'm surprised by some of them. For example, go vet nominally catches misuses of mutexes, so it's surprising that even a few of those slipped through. I wonder if those situations are a bit more complicated than the example.
Obviously, the ideal outcome is that static analysis can help eliminate as many issues as possible, by restricting the language, discouraging bad patterns, or giving the programmer more tools to detect bugs. gVisor, for example, has a really interesting tool called checklocks:
While it definitely has some caveats, ideas like these should help Go programs achieve a greater degree of robustness. Obviously, this class of error would be effectively prevented by borrow checking, but I suppose if you want programming language tradeoffs more tilted towards robustness, Rust already has a lot of that covered.
Good point. Right now I kind of see modern programming as two fold:
1) Loosely typed to get you what you want faster, but with some mistakes, and
2) Strongly typed that forces you to try harder, but ultimately better
I'm usually happier with the latter. I find I become far more frustrated when I try to write python than I do something like Rust just because I know when I write Python that I will have mistakes I'll have to fix in prod, vs when I write Rust I won't have those mistakes (although it'll take me longer to get something to prod)
I greatly prefer Rust to Python, but slightly prefer Go to Rust in many situations. Python even with MyPy just feels sloppy, whereas Go does offer decently strong typing at least. As for Go vs Rust, the answer is in the ecosystem, and I blame that on the difficulty of maintaining high quality Rust crates. I know not everyone agrees with this explanation, but I think Rust being complicated makes it hard to offer zero compromises libraries for it that fit the spirit of the language. Every single piece of the ecosystem has its little issues. Today I found out the most prominent websocket library in Rust does not support permessage-deflate yet. Not a huge deal, but it does happen to be an issue for a use case I had in mind. The last few times I wrote stuff in Rust, I ran into similar problems:
- Sqlx is cool; it’s similar to sqlc but with proc macros. Unfortunately, it requires and connects to PostgreSQL… during compilation.
- The GIF crate works, but it’s kind of slow. It seems that image processing may be a little difficult to optimize safely. Also, alarmingly, I ran into a bug that broke the output in only in production builds… (only in higher opt levels.)
- Sometimes, the dependency trees start to look like npm. Understandably, the standard library for Rust is not quite as big as Go.
Go has a lot of great stuff in the ecosystem. There’s the standards library, with great crypto implementations, implementations of various common file formats and markup languages, etc. there’s a pretty good library for parsing raw packet capture, gVisor has a robust TCP stack and a mutex lock checker, there’s tons of linting tools, and golangci-lint ties a lot of them together, sqlc.dev and buf are useful for writing services, and there’s plenty of native Go client libraries for databases, queues, etc. whereas for Rust it seems you’re more likely to be stuck with C bindings, or occasionally worse.
It’s great that Rust is so good at integrating with C code; it may even be better for consuming C libraries than C. However, it is a damn shame that for a lot of stuff in production environments, you are still going to need to fall back to C today.
Rust feels like the perfect language to go nuts in and build the future. It has some issues (my big two are async being kind of stinky and no placement new) but by and large, nobody, even I, a big Go zealot, would deny that Rust feels like the future. If I had to pick a language for a project where I had unlimited time and budget to do it right, it’s Rust every single day.
That said… Today, at least for writing services and command line tools, Go feels like a good tradeoff for people with deadlines and decent standards. I use Go at work, and I have been doing so for almost a decade now. Do I spend time on problems that are wholly preventable by better language design? Absolutely. Does Go save me time by being simple as hell, having a rich ecosystem and compiling very quickly? Also yes.
I do hope to have more projects where I can make effective use of Rust. I have one I’ve been trying to get going for a while, where Rust’s attention to detail and robustness would be amazing to have, and it’s in an environment where Go would not work well. That said, it always proves to be at least a little challenging it seems.
OT: sqlx tip: you can compile without a DB connection by either using the non-macro version of the queries (at the cost of losing compile time query checking) or you "bake" the query checks using sqlx-cli which produces files that you can check into your repo and allow the macros to compile offline. In that case you only need to re-connect to the DB when the SQL queries change.
There are no gradients of strong typing. Either a language is strongly typed or not. Python is strongly typed.
For someone with such strong opinions, you seem to lack certain fundamental knowledge which I suggest you rectify ASAP as it will definitely improve your programming skill.
The phrase “strongly typed” does not have one single agreed upon definitions. I’ve known that for like over a decade, since it comes up extremely often when someone is upset about people not liking x language and they have to jump to semantic debates instead of debating about real problems. I assume you’re not doing that… so I can clear things up: instead of “strongly typed”, substitute in “statically typed”.
edit: Also,
> There are no gradients of strong typing
that's flatly untrue. There certainly is a notion of 'stronger' vs 'weaker'. I don't know where you got this idea from.
I'm surprised by some of them. For example, go vet nominally catches misuses of mutexes, so it's surprising that even a few of those slipped through. I wonder if those situations are a bit more complicated than the example.
Obviously, the ideal outcome is that static analysis can help eliminate as many issues as possible, by restricting the language, discouraging bad patterns, or giving the programmer more tools to detect bugs. gVisor, for example, has a really interesting tool called checklocks:
https://github.com/google/gvisor/tree/master/tools/checklock...
While it definitely has some caveats, ideas like these should help Go programs achieve a greater degree of robustness. Obviously, this class of error would be effectively prevented by borrow checking, but I suppose if you want programming language tradeoffs more tilted towards robustness, Rust already has a lot of that covered.