- estebankIn an emergency, if the only options are taking time moving things out of the way or not being able to move, you move things out of the way.
- If I invite you to a barbeque and tell you I made lunch, will you tell me off because I didn't raise and butcher the cow?
- > Any large Rust project I check has tons of unsafe in its dependency tree.
This is an argument against encapsulation. All Rust code eventually executes `unsafe` code, because all Rust code eventually interacts with hardware/OS/C-libraries. This is true of all languages. `unsafe` is part of the point of Rust.
- Having a 3D engine does not a AAA make. The Witness is a beautiful looking game, but the amount of state and interactions it has to deal with is orders of magnitude less than GTA: San Andreas. It is closer to the complexity a Myst remake would have.
- This reads to me like an argument for better refactoring tools, not necessarily for looser type systems. Those tools could range from mass editing tools, IDEs changing signatures in definitions when changing the callers and vice versa, to compiler modes where the language rules are relaxed.
- The output will cause no user visible change.
It uses ASCII for all output, replaces ZWJs to have consistent terminal output in the face of multi codepoint emoji for two out of the top of my head.
- If you want something more conservative for error reporting, annotate-snippets is finally at parity with rustc's current custom renderer and will soon become the default for both rustc and cargo.
- It would be similar, pointing at the other argument. Neither case would have an applicable suggestion, just point in the right direction. I don't know if at the time we emit the error for `pick_first` we're able to evaluate the function's body to see if changing the lifetimes is feasible or not.
- Would output along the following lines be an improvement?
error[E0597]: `buffer` does not live long enough --> src/main.rs:63:21 | 59 | let report = { | ------ borrow later stored here 60 | let mut buffer = Vec::new(); | ---------- binding `buffer` declared here 61 | let ctx = Context { 62 | config: &config, | ------ this field and `buffer` are required by `Context` to have the same lifetime 63 | buffer: &mut buffer, | ^^^^^^^^^^^ borrowed value does not live long enough ... 68 | }; | - `buffer` dropped here while still borrowed help: consider making different fields in `Context` have independent lifetimes | 4 | struct Context<'a> { | ^^ 5 | config: &'a Config, | ^^ 6 | buffer: &'a mut Vec<u8>, | ^^ 7 | } - If you have a good repro case, I'd appreciate a bug report. Bad diagnostics are considered bugs.
- A hand saw, a table saw and a SawStop are all tools, but they have different characteristics even though they all are meant to cut the same wood.
- > What user benefit are they promising?
From their README, they promise better error messages, extensions when relevant (example: --progress), and Linux, macOS, Windows and other platforms support. It is my understanding that the GnuWin32 coreutils were last updated in 2017 and had some subtle differences to regular GNU coreutils, so that's one set of users for whom there's clear benefit. Faster speed could be accomplished if architectural changes are viable, but for many of these tools they are IO-bound.
- > uutils coreutils aims to be a drop-in replacement for the GNU utils. Differences with GNU are treated as bugs.
> Our key objectives include:
> Matching GNU's output (stdout and error code) exactly
> Better error messages
> Providing comprehensive internationalization support (UTF-8)
> Improved performances
> Extensions when relevant (example: --progress)
> uutils aims to work on as many platforms as possible, to be able to use the same utils on Linux, macOS, Windows and other platforms. This ensures, for example, that scripts can be easily transferred between platforms.
Experimenting with better error messages, as test-bed for extensions that might not be able to be tried or accepted in GNU coreutils (for technical, social or other reasons), and being able to use the same tools in all major OS are very reasonable divergences from GNU's project to "justify" its existence.
The project was originally just a learning project for someone who wanted to learn Rust by reimplementing tools that were small, not a moving target and useful. From there, it grew as it found an audience of developers interested in productionalizing it. There have been coreutils ports for the languages you mention (go-coreutils, pycoreutils, coreutils-cpp, etc.), they just didn't (yet?) hit critical mass. It is a harder sell for GC-based projects in this case because they are unlikely to ever be included as part of a dirtribution's base. Lets not forget that coreutils themselves are a rewrite of previously existing tools to begin with.
- "unsafe" or `unsafe`? One is the general meaning of the word, the latter is "it invokes undefined-behavior".
- Measuring success of a project against a bar that the project didn't set is like complaining that an F1 car is hard to park: that's not what it was meant to do.
Servo was meant to be a test-bed for new architectures that might or might not be usable by Firefox. It was never meant to become Firefox' new web renderer, and it wasn't until more recently and long after the Mozilla-pocalypse that a new team took over the project with a goal of productionalizing the project as a whole. Stylo, for example, was integrated into Firefox 57 and allowed for parallel CSS style calculation, an effort that was tried unsuccessfully multiple times in C++.
- > For an example, if a function in no_std overflows, it can result in undefined behavior, no unsafe required. And stack overflows are easy in Rust, like they are easy in most other systems languages.
This is true, no_std has no Rust runtime so it doesn't provide stack protection. I am aware of efforts to address this for embedded, but they're not available at the moment.
> Steve Klabnik has lied about that in the past, as he is wont to do.
1) I don't know what Steve has to do with anything I asked so it is bizarre to bring up and 2) I find this is to be a ridiculous statement.
- Does every discussion of Rust and C need this recurring subthread conversation? It is approaching Groundhog Day levels of repetition. Yes, `unsafe` code can have memory safety bugs. Yes, `unsafe` doesn't mean "unsafe". Yes, a sufficiently advanced C-developer can have a sufficiently advanced C-codebase with reduced probability of bugs that might be even better than an insufficiently advanced Rust-developer. Yes, regular safe-Rust isn't the same formal verification. Yes, Rust doesn't catch every bug.
On the other hand, most developers have no need of writing `unsafe` Rust. The same tools used for static and dynamic analysis of C codebases are available to Rust (ASAN and friends) and it is a good idea to use them when writing `unsafe` (plus miri).
The reason I'm replying is that "the impact of Rust on memory safety" is always a conversation that gets outsized amounts of ink that it drains focus away from other things. I would argue that sum types and exhaustive pattern matching are way more important to minimize logic bugs, even if they aren't enough. You can still have a directory traversal bug letting a remote service write outside of the directory your local service meant to allow. You can still have TOCTOU bugs. You can still have DoS attacks if your codebase doesn't handle all cases carefully. Race conditions can still happen. Specific libraries might be able to protect from some of these, and library reuse increases the likelihood of of these being handled sanely (but doesn't ensure it). Rust doesn't protect against every potential logic error. It never claimed to, and arguing against it is arguing against a strawman. What safe-Rust does claim is no memory safety bugs, no data races, and to provide language and tooling features to model your business logic and deal with complexity.
- > But with no_std, Rust is not memory safe, even when not using unsafe.
What makes you say that?
- > I can't even get Rust to work here on my slightly older Mac system.
Could you elaborate on that? macOS Sierra (released on 2016) on Intel macs is supported[1][2], which should allow for Macs from late 2009 onward to work. The Intel Mac build is no longer Tier 1 because the project no longer has access to CI machines for them, and 32-bit cross building is hampered by Xcode 14 not shipping the corresponding SDK[3].
1: https://github.com/rust-lang/compiler-team/issues/556
2: https://doc.rust-lang.org/nightly/rustc/platform-support/app...
- I take umbrage at "The error that teaches nothing". I went to reproduce the case[1] in order to file a diagnostics ticket, and I don't know how you could make this diagnostic any more pedagogical:
> The compiler catches this. Good. But the fix isn't "add a mutex" - you already have a mutex.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 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:
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: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`
I just created a ticket to better gate that suggestion so it doesn't trigger here[3].// 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`.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