Rust code is significantly more readable. Use the type system to your advantage.
> - - really smart type inference
Rust has really smart type inference too and only rarely ask for an explicit type. I've found that I prefer annotating my types. It adds to documentation and readability.
> - a bunch of time thinking about the borrow checker
You can use Arc/Mutex to overcome some of these and review them in a refactoring.
Rust has smart type checking. The really smart stuff is (IMO) the beauty of the borrow checker.
In PHP, modern typecheckers can verify that the first element always exists on an array after an emptiness check:
if ($some_arr) {
echo reset($arr);
}
Whereas in Rust you have to explicitly unwrap:
if !some_vec.empty() {
print!("{}", some_vec.first().unwrap());
// .. more code
}
The Rust version requires you to use your intuition to figure out that `unwrap()` will never panic here.
In my Rust port I consistently rely on the PHP typechecker's knowledge of the equivalent code when using `unwrap()`, because it knows which array fetches are safe.
> At the cost of introducing a bug/technical debt.
At the cost of shipping a product!
-------
Edit: user ibraheemdev proposes this Rust equivalent which more closely matches the idealised pseudocode, and type-checks:
if let [first, ..] = &some_vec {
print!("{}", first);
// .. more code
}
It's preferable IMO to
if let Some(first) = some_vec.first() {
because the latter relies on a property of a non-empty vec, and checks that property, rather than checking the non-emptiness of the collection.
> The Rust version requires you to use your intuition to figure out that `unwrap()` will never panic here.
You should not use `unwrap` in a production product. It's there for prototyping and I think it's a mistake they have it (though the language already requires a good upfront time investment as it is). Use `?` and have your error propagate accordingly to the top of the chain. Have your own error types and convert from other error types.
if !some_vec.empty() {
print!("{}", some_vec.first().unwrap());
// .. more code
}
I don't know why you would check the first element of a vector. Use Rust type system to your advantage, and don't "convert" PHP code into Rust. Re-design your program. Also you don't need to check that the Vector is empty if you are using "first". "first" returns an Option with None if your vector is empty. My guess is that you have yet to exhaust the idioms Rust offers and approaching it in a PHP-like manner.
> > At the cost of introducing a bug/technical debt.
We tried this style in one of Google Earth's packages for a while (using an internal C++ class similar to Rust's Result). So many operations could theoretically fail (e.g. indexing out of bounds or an expected key not existing) that pretty much every single function in that package returned a Result. These "unexpected" errors would just fly up the stack, manually unwinding it, because nobody could really do anything with them. Once we had that, I really questioned some of our policies.
I can imagine a language where panics don't crash the entire application, but instead blast away the surrounding "region" of memory, leaving the rest of the program intact and able to keep running. Similar to catch_unwind, but if the language is aware of region boundaries, and only allows certain methods of communication between them, it would leave the rest of the memory in much more predictable possible states.
It may sound surprising, but it's actually possible with the right language constructs (Erlang folks know what I'm talking about!) and that way, we could once again have panics for unexpected errors, and Results for expected errors.
> don't "convert" PHP code into Rust. Re-design your program.
Trust me, I am!
For example, I'm rewriting all the (very-efficient) PHP regex code to a much more convoluted version because Regex::new is so costly.
Less sarcastically, I am embracing the Rust Way where necessary. My complaint is that the Rust Way sometimes forces me to depart from the idealised pseudocode version of a given algorithm much more drastically than PHP does.
> Yes, but IMO that makes the code a bit more abstract:
> You've left behind an explicit "is this collection non-empty" and you're instead relying on a property of a non-empty collection.
More abstract for who? I think virtually all Rust programmers would easily understand the `if let` snippet, virtually all PHP programmers would understand the PHP snippet, and virtually all programmers of any language would understand that a non-empty array has a first element. I'm not at all convinced that most programmers would correctly guess that a function called `reset` is used to access the first element in an array though.
A collection is non-empty if and only if it has a first element. Therefore checking for non-emptiness is the same as checking for the existence of a first element.
I think that's obviously a matter of opinion. I don't think Rust is hard to read at all, nor do I think of it as being particularly sigil heavy, but that's me. I think the syntax is probably unfamiliar for some, and familiarity is almost always what people mean when they say "readability".
Coming from c++, Rust was pretty familiar. PHP isn't that hard to read either.
Most Rust programmers just never, ever have to deal with pointers like this. And most code in the wild looks nothing like this. Yes, it's there if you need it, but in practice you will never read anything like it.
Readability is the most suspect of all the anti-Rust arguments to me, because, as others have noted, it's almost always about familiarity. The most senior parent comment is someone explaining how their 100KLOC PHP command line program(!) was more concise and readable than Rust! PHP as the exemplar of readability. Think about that.
Look -- if I really loved PHP and was forced to write Rust, I might really hate it. But I think the world of people who really love PHP is pretty small compared to the world of people who have lived with PHP because that was what was familiar. Folks let's climb off the bus to crazy town.
Depends. Rust is quite readable for a low-level language that does expose every little bit of detail of memory-management. But I do agree that we should not over-promise its readibility.
> - concise, readable code
Rust code is significantly more readable. Use the type system to your advantage.
> - - really smart type inference
Rust has really smart type inference too and only rarely ask for an explicit type. I've found that I prefer annotating my types. It adds to documentation and readability.
> - a bunch of time thinking about the borrow checker
You can use Arc/Mutex to overcome some of these and review them in a refactoring.
> - ease of iteration
At the cost of introducing a bug/technical debt.