> that are nothing even remotely close to systems programming
This is unnecessary gatekeeping. It also shows your lack of perspective. Or, rather, your lack of imagining other perspectives, probably.
Sure, rust is primarily a language aimed at systems programming. But it also is so much more (and also a cult).
* Its type system is excellent. Especially the lack of a "null". Even if, like me, you're fine with a GC, the type system alone is worth dealing with this insistent borrow-checker.
* Its multithreading is stellar. The borrow checker helps a lot in making it such.
* Its mutable/immutable model is highly practical. It's what makes the threading stellar and the type system more useful than in any other language I worked with.
* Its "oop" model is uncomfortable at first (coming from Ruby and Java) but forcing the "composition over inheritance" by not having inheritance is probably the best thing that can happen to "OOP". Every solution where I used inheritance, I shouldn't have.
* Its culture of "making the good way the easy way", being opinionated, and a community that adheres to this, is worth dealing with a thousand borrow-checker WTFs. cargo fmt, clippy, etc.
* Its build system that generates binaries that can just be "plopped" onto a server, "chmod +x" -ed, and ran is unprecedented.
I come from Ruby, Java, Javascript (typescript). I do a lot of Python, maintain some go services, have decades of PHP under the belt and occasionally dabble in some C and even C++. I can find my way around in a C# codebase and Objective-C.
All have their strengths and weaknesses. Their place and use-cases.
But rust, for me, is the only "ecosystem" that ticks all checkboxes in nearly all situations. It has downsides, and I consider the borrow-checker to be one of them in a lot of my use-cases, but it's something I'm willing to deal with gladly, because rust's other benefits.
a few months ago there was an article linked here on HN (iirc about rust game dev) that argued that while rust is great, it's virtue of being mostly correct every time can also be a weakness.
the argument was that in early dev and prototyping phases you don't want to write good, clean, correct code but move fast and break things while not caring about edge cases - and this, the author argued - is relatively hard in rust.
I partially agree. It's not so hard to write software that keeps the borrow checker happy in early stages. But it does restrict the freedom to make terrible decisions a bit. Sometimes in that stage terrible decisions are OK.
But I do like that even in this stage, one is forced to at least make the decision to have terrible things, explicit. Like with 'unwrap()' and 'expect()' littering the code in PoCs and exploratory projects.
For me, a bigger problem in this stage is that I lack the information to make decisions on types. I have this same problem in TS and Java. It's guaranteed that I'll shape types in ways that will prove difficult, or slow me down a lot next week. I'll be spending time refactoring types when I should move on to the next feature.
I guess, but that's just my experience, that statically typed languages are just not well suited for early stage software. When we don't know the shape of the data we'll be pushing around, nor know anything about the shape of the layers, ports, modules and so on. Which is why I'll grab ruby for these kind of quick explorations often. And once the shapes emerge, rewrite it in rust :)
I agree with you on the borrow checker... Part if me wants a simplified(distilled?) Rust ... All of the good stuff, but remove the bad... Not sure how that looks but it is something I know I want
A lot (all?) of the points I make aren't unique to rust, or even invented in rust. Many have even better implementations in other languages. Go also invented the "fmt", with one opinionated code style "enforced" by default - bikeshedding be gone!
My point was that it's the combination of all of these points. AFAIK, go ticks many of these boxes too. But for me golang falls short with mutability, and with the type system (though that one's catching up really fast). It's the "package-deal" that I like about rust.
I much prefer rust to go for many reasons, but IME go gets this part much better. Darwin / Linux cross compilation, armv7, FreeBSD, oh sorry you don't have a linker for that toolchain, wait where are those OpenSSL headers... lots of cross-compilation targets I've done in minutes with go that scp and run right away that end up being days / weeks of adventures to cross compile in rust, in spite of me knowing rust much better than go at this point.
I have had the luxury to work in projects that don't have to target many platforms, but rather "one": a server. Which then is often a simple linux variant so setting up a CI or even the local build to target that "one" is relatively simple.
But wasn't Go a lot more limited in the amount of targets it can build for than rust?
Yes and no -- obviously I can build for no_std targets like esp32 and atmega128p in rust but not go (haven't tried tinygo), but the proportion of targets that successfully built and ran IRL has been higher for me with go. On rust, the dynamic linking of libc (by default) and failure to include a linker with the toolchain have repeatedly been stumbling blocks, go "just works."
I didn't mean syntax or core lib to be similar, I just generally meant that both languages impose restrictions on themselves which might seem sensible at first.
Java isn't that restrictive. Rust's type system is much more restrictive and customizable.
That said, a good way to think about programs is a series of restrictions, i.e. invariants. Truth be told, only Ada Spark so far really embraced invariants.
This is unnecessary gatekeeping. It also shows your lack of perspective. Or, rather, your lack of imagining other perspectives, probably.
Sure, rust is primarily a language aimed at systems programming. But it also is so much more (and also a cult).
* Its type system is excellent. Especially the lack of a "null". Even if, like me, you're fine with a GC, the type system alone is worth dealing with this insistent borrow-checker.
* Its multithreading is stellar. The borrow checker helps a lot in making it such.
* Its mutable/immutable model is highly practical. It's what makes the threading stellar and the type system more useful than in any other language I worked with.
* Its "oop" model is uncomfortable at first (coming from Ruby and Java) but forcing the "composition over inheritance" by not having inheritance is probably the best thing that can happen to "OOP". Every solution where I used inheritance, I shouldn't have.
* Its culture of "making the good way the easy way", being opinionated, and a community that adheres to this, is worth dealing with a thousand borrow-checker WTFs. cargo fmt, clippy, etc.
* Its build system that generates binaries that can just be "plopped" onto a server, "chmod +x" -ed, and ran is unprecedented.
I come from Ruby, Java, Javascript (typescript). I do a lot of Python, maintain some go services, have decades of PHP under the belt and occasionally dabble in some C and even C++. I can find my way around in a C# codebase and Objective-C. All have their strengths and weaknesses. Their place and use-cases.
But rust, for me, is the only "ecosystem" that ticks all checkboxes in nearly all situations. It has downsides, and I consider the borrow-checker to be one of them in a lot of my use-cases, but it's something I'm willing to deal with gladly, because rust's other benefits.