Yes, C has an ISO standard. It took more than 15 years from the conception of the language. Same with C++. Before that, there didn't even exist a normative compiler. And if you want a certified C or C++ compiler, you have to pay a lot, or use the "it is wildly used with a well-known set of bugs".
Either way, there's a huge load of constructs that are Undefined Behavior which you need to know about and avoid. The discussion about the borrow checker being hard to understand and work around, only highlights a belief that is different from what you need to do in C or C++ anyway - but without help from the compiler.
And cost? Heck, Visual Studio Pro cost twice that of Ferrocene. The Enterprise version starts at 10x the price - and those aren't certified.
Then there's the discussion about proving to the compiler that the code is correct - while at the same time dismissing proof using formal verification, that in turn is an entire language and alphabet of symbols that doesn't even exist on a keyboard.
Yes, the Rust syntax could have been easier to read, to that I agree. And Rust is no silver bullet. But in general, the article could benefit from a review.
I remember only a single breakage of previously compiling code with the time crate because of a change in type inference, but even there the compiler told me to update the lib. And that’s in 6 years of using Rust.
Maybe true, but rust is currently the closest thing we've got. It may eventually grow into the language you're describing. This article very much feels like someone who doesn't have a ton of experience writing software complaining that proscriptive standards don't exist. The reason so much undefined behavior exists in the ISO C and C++ standards is because the programming community is still learning. And we're still learning.
Also measuring a proof of concept by LOC of all metrics just tells you to completely ignore this blogpost as utter bs. No sane person should use LOC as a metric for anything. Linus Torvalds recently said that himself.
- C "standard" is quite flaky in practice, there are lots of un/underdefined things that compilers interpret quite liberally for the purpose of optimisations
- complaining about the syntax and symbols is unfair: rust offers all these semantics to represent the memory model of your codebase. The equivalent is not possible in C/C++, and when we try to do it, we're inventing our own constructs at the code level instead of relying on the syntax
probably, the push method should return a boolean indicating whether the task could be enqueued and if the capacity is reached then the task is not enqueued. but this is c so its very easy to write buggy code :) also, in this case the caller has no obvious safe way to check whether the queue method is safe to call so the author can't claim its up to the caller to verify some pre-condition before enqueuing a task.
error[E0382]: use of moved value: `results`
--> src/main.rs:30:22
|
22 | let results = Arc::new(Mutex::new(Vec::new()));
| ------- move occurs because `results` has type `Arc<std::sync::Mutex<Vec<i32>>>`, which does not implement the `Copy` trait
...
28 | for i in 0..20 {
| -------------- inside of this loop
29 | // let results = Arc::clone(&results);
30 | pool.execute(move || {
| ^^^^^^^ value moved into closure here, in previous iteration of loop
31 | let mut r = results.lock().unwrap();
| ------- use occurs due to use in closure
|
help: consider moving the expression out of the loop so it is only moved once
|
28 ~ let mut value = results.lock();
29 ~ for i in 0..20 {
30 | // let results = Arc::clone(&results);
31 | pool.execute(move || {
32 ~ let mut r = value.unwrap();
|
help: consider cloning the value before moving it into the closure
|
30 ~ let value = results.clone();
31 ~ pool.execute(move || {
32 ~ let mut r = value.lock().unwrap();
|
> The compiler catches this. Good. But the fix isn't "add a mutex" - you already have a mutex.The compiler doesn't tell you to "add a mutex".
Trying the first suggestion blindly does lead to a sadly very verbose output in an effort to try to explain all the moving parts of the API:
error[E0277]: `std::sync::MutexGuard<'_, Vec<i32>>` cannot be sent between threads safely
--> src/main.rs:30:22
|
30 | pool.execute(move || {
| ------- ^------
| | |
| ______________|_______within this `{closure@src/main.rs:30:22: 30:29}`
| | |
| | required by a bound introduced by this call
31 | | let mut r = results.unwrap();
32 | | r.push(i);
33 | | });
| |_________^ `std::sync::MutexGuard<'_, Vec<i32>>` cannot be sent between threads safely
|
= help: within `{closure@src/main.rs:30:22: 30:29}`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, Vec<i32>>`
note: required because it appears within the type `Result<std::sync::MutexGuard<'_, Vec<i32>>, PoisonError<std::sync::MutexGuard<'_, Vec<i32>>>>`
--> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:550:10
|
550 | pub enum Result<T, E> {
| ^^^^^^
note: required because it's used within this closure
--> src/main.rs:30:22
|
30 | pool.execute(move || {
| ^^^^^^^
note: required by a bound in `ThreadPool::execute`
--> src/main.rs:15:23
|
13 | fn execute<F>(&self, f: F)
| ------- required by a bound in this associated function
14 | where
15 | F: FnOnce() + Send + 'static,
| ^^^^ required by this bound in `ThreadPool::execute`
The code that produces that first suggestion does have this comment I left there a year ago (because it was meant to help with a very different case)[2], so clearly I suspected the logic to be not completely correct back then, but likely not realized just how much so: // FIXME: We could check that the call's *parent* takes `&mut val` to make the
// suggestion more targeted to the `mk_iter(val).next()` case. Maybe do that only to
// check for whether to suggest `let value` or `let mut value`.
I just created a ticket to better gate that suggestion so it doesn't trigger here[3].But the second suggestion is exactly what the user intended. The only thing missing would be for the message to actually mention "that Arc::clone() creates a new owned handle that can be moved into the closure independently" as part of the message. That gives makes me think we should have something like `#[diagnostic::on_move("message")]`, so I filed a ticket for that too[4]. At worst we could hardcode better messages for std types.
I am not impressed with the rest of the article, neither the tone nor the substance. I wouldn't have commented if it hadn't been due to the combination of the title with that specific wording (given that I've spent a decade making rustc errors teach you things), the actionable feedback being buried under layers of snark and indirection, and the actual feedback being given being wrong (but hey, at least I did find two other tangential things that could do with fixing, so small wins I guess?).
[1]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
[2]: https://github.com/rust-lang/rust/pull/121652
[3]: https://github.com/rust-lang/rust/issues/149861
[4]: https://github.com/rust-lang/rust/issues/149862
Edit: found the logic error. for loops desugar to a bare loop with a break, and the selection logic didn't account for that. https://github.com/rust-lang/rust/pull/149863
"C/C++ (Experienced Developer)
Resource management is internalized. It's like driving a manual transmission - you don't consciously think about shifting gears, you just do it."
How is this not saying that C/C++ require highly skilled developers? Why is there not an equivalent "Rust (Experienced Developer)" section for those who internalise the borrow checker model and can use their freed-up cognitive powers for the same things the experienced C/C++ developer can? This is a double standard.
And like wow, CloudFlare had one outage where they messed up config file parsing. Good thing nobody coding in C++ ever shipped a bug that caused an outage!
I actually think I agree with a lot of the substantive criticisms this article makes of Rust, but man, it is so overstated and melodramatic.
evanjrowley•6d ago
Is the year mentioned in "The Cloudflare Paradox" section correct?
Same question for the "2035 compile / 2015 code" cell in the lower-left side of the table in "The Elephant in the Room: Rust Has No Standard" section.
steveklabnik•6d ago
The cell is based on making it up. It’s suggesting a number in 2035. We aren’t in 2035 yet.
I don’t think these points are good. They wildly extrapolate from some things that are technically correct, but miss nuance.
As one example, in that table, Rust is marked as “pay ferrocene” in red while C is marked as “yes.” Yet you’ll also pay for a qualified C compiler. These are equivalent.
It also pretends that an ISO specification matters specifically, as opposed to anything else. You’d believe that a C++ codebase will compile without modification indefinitely in the future simply because it has an ISO specification, but in the real world, both the specification and implementations have non-zero breakage, just like how Rust doesn’t have an ISO specification yet has very little real word breakage.