"If it compiles it works" happens often to me, which is why I'm such a fanboy.
For this reason I'd be much more comfortable jumping into an unknown Rust code base than anything else.
"If it compiles it works" happens often to me, which is why I'm such a fanboy.
For this reason I'd be much more comfortable jumping into an unknown Rust code base than anything else.
Rust also promotes simple control flow and acyclic data structures by making writing complex control flow and cyclic data structures extremely hard. Its tpe system is also very explicit about who owns what and about sharing.
Imagine you see the following Python function for the first time:
def foo(x: Bar):
foobarize(x)
Although you're lucky that someone included the type annotation for x, and you might know what Bar really is, you still can have no idea whether e.g you can safely modify x in this function. Because maybe something else holds another reference to this very same instance and will be confused if the object suddenly changes here.In Rust if you encounter:
fn foo(x: Bar) {
foobarize(x);
}
you know there is nothing else holding x, and this function can do whatever it likes with it. You can very quickly deduce who owns what, what is shared and what is not shared. IMHO this helps understanding complex systems very much.It's a very compelling thing about Rust that problematic designs are clearly marked with boilerplate, so you know exactly what to look for and perhaps refactor. There isn't really a close equivalent to this in other languages, e.g. in C++, the "modern" facilities you're supposed to use have the heaviest syntax, and this is often true in Python, Ruby, JS etc.
You're right... but just to add.
In any Enterprise project involves a lot of talking to other systems(think Salesforce, Netsuite, Slack) or implementing existing protocols(SAML, OAuth,LDAP) and other such things. Python being popular for very long means there's prior work in almost every area. I believe this can be one definition of "productive", basically re-using something existing and spend your time on other better things. In a lot of the same projects performance at the CPU level might not be a bottleneck because you're stuck waiting 10 seconds for an API call to Salesforce.
I'm more excited about PyO3 and other Python+Rust advances, where it seems you can offload lot of CPU intensive stuff to Rust but keep the Python layer and its ecosystem.
Of course in most projects one or the other usage dominates so my glib response isn't particularly compelling, but in my current project we do use a similar amount of both.
But we still have some Python Django code and will probably end up with C in driver code.
For a backend webservice prototype, that's probably true. It's not true for everything, though. Especially if there are performance requirements or you need to handle errors properly.
I've found Rust to be extremely productive for implementating interpreters, for example, thanks in no small part to algebraic data types and pattern matching. It's not quite as ergonomic as Haskell/OCaml, since you can't currently match under Box's, but hopefully that feature will get stabilized soonish.
I also have used it for computationally intensive apps, such as a poker odds calculator. Going from a single threaded ~24 hr runtime to a ~15 min runtime on 96 vCPU took a few minutes, thanks to rayon. Of course C/C++ with openmp loop annotations is similarly quick for trivially parallel problems, but Rust's built in unit testing and package management make me far more productive for things like this than in C/C++.
The reason is most things are immutable. Frankly I’m just not used to writing code in that way (even though most of my scripting code is functional and not imperative). I find that when I refactor my Rust it requires significant work.
In mutable code I can just modify a class/struct when something needs to change but when it’s mostly immutable those changes often require significant redesigns.
Perhaps this is just because I’m new to Rust, but that’s just proving my point that it’s hard. I’m better setup to learn a new language than the majority of programmers for sure and it’s been a real struggle.
At this point I would probably be struggling as much in a language like Haskell I suspect. My issue isn’t the borrow checker, it’s immutability.
You do have to explicitly declare them mutable, though, and will warn you if you have a mutable variable that you never mutate. This is helpful for avoiding surprises.
Scale up a bit, and you end up with far fewer (often zero) subtle bugs when other people change other parts of the codebase, or when you do a significant refactor - some of these being the kinds of bugs that are difficult to test for.
I would call that "more productive", personally.
This completely ignores domain / logic /algorithmic errors which in my experience completely dwarf types of errors Rust is supposed to take care of.
On the other hand, Google reports that "to date, there have been zero memory safety vulnerabilities discovered in Android’s Rust code." Source: https://security.googleblog.com/2022/12/memory-safe-language...
But overall I agree: you need tests for business logic.
Another thing that Rust gets right is that you're incentivised to write some tests right in the same file where you're writing the implementation (it just works out of the box with cargo test), so even complex logic is easy to test out.
You don't have to go through the "oh, let me setup mocha to add a test... never mind I won't bother right now"
I assume this goes for scripting languages with weak / no typing.
>"You don't have to go through the "oh, let me setup mocha to add a test... never mind I won't bother right now""
Same thing.