3 ms·
Relegating parts of the memory model with unclear/hard-to-specify semantics (i.e. relaxed or consume) to the "unsafe" part of the language is an interesting ide
by Hercuros 5y ago
Relegating parts of the memory model with unclear/hard-to-specify semantics (i.e. relaxed or consume) to the "unsafe" part of the language is an interesting idea, but it kind of goes against the spirit of "unsafe" (this point is debatable, of course).
The purpose of the unsafe keyword is to mark code that could cause safety issues (undefined behavior) if its expectations about the surrounding code are not met. (e.g., an unchecked array access expects its index to be in bounds).
With unlimited time and resources, it should be possible to give a mathematical proof about those unsafe blocks, showing that their expectations are met and that undefined behavior will not actually occur (by for example proving that the array index supplied will always be in bounds).
But since relaxed and consume have unclear semantics, it hard to formally reason about the correctness of any code that uses them (and it is also hard to build tools to do that checking, as mentioned).
So in an ideal world, we would have a 100% clear semantics for all parts of the language, _including_ the unsafe fragment. Unsafe should not be a place to put poorly specified languages features.
Of course, we don't live in this ideal world, but I would rather hope for fixing the memory model so that it be made completely formal and precise (if necessary, giving up some currently allowed compiler/hardware optimizations if they're more trouble than they are worth). As an extreme example, sequential consistency is easy to understand as long as you don't mix it with other types of atomic accesses and avoid non-atomic data races.
- nybble41 5y ago> The purpose of the unsafe keyword is to mark code that could cause safety issues (undefined behavior) if its expectations about the surrounding code are not met. That is one use of the `unsafe` keyword. You see this version in the qualifiers for unsafe functions, where safety depends on the inputs and other context. It means that the marked function cannot be called from safe code. The `unsafe` keyword is also used to mark code blocks where the content of the block must be manually proved to be safe, even for valid inputs—this includes calls to unsafe functions, dereferencing raw pointers, etc. (Unsafe functions use this mode by default.) The same keyword is also used to mark unsafe traits and their implementations, where an incorrect implementation of the trait—even the members which are not themselves marked as `unsafe` and thus can be called from safe code—can impact the safety of other parts of the program (via unsafe code blocks or unsafe functions). An example of this would be a trait with a member which returns a raw pointer (itself a safe operation) which is then called from within an `unsafe` block and dereferenced.
- tialaramex 5y agoAnd another quite different thing people do with "unsafe" is label code that is, from Rust's point of view, entirely safe, but which has important practical problems they want its callers to pay attention to. Perhaps openHellPortal is complicated enough that you feel it should be a separate function. On the other hand, you want to be clear that nobody should expect openHellPortal to check the necessary precaution are in place. So, mark openHellPortal unsafe and provide a safe wrapper SafeHellPortal which internally calls openHellPortal after checking some necessary precautions are in place and ensures closeHellPortal is called when appropriate too. As far as I know nobody builds hell portals with Rust (You have to assume there'd be a HN post about it right?) but they do plenty of embedded systems development, and those people use unsafe this way. Twiddling the SOC's interrupt controller is nothing to Rust itself, but the people writing the interrupt controller twiddling code can mark it "unsafe" and explain what callers must do to avoid chaos. Then callers can obey those instructions and make a safe wrapper for a particular purpose e.g. "SerialPort", and the average developer needn't even know that under the hood randomly twiddling the interrupt controller causes everything to catch fire, because they're using a safe SerialPort abstraction which can't cause that even if they hold it wrong.
- Hercuros 5y agoHaving "unsafe" mean "can wreak havoc if used incorrectly" is fine, as long as it's clear what constitutes incorrect usage, and what the behavior of correct usages is. And it does not have to be clearly defined what "havoc" is (just like undefined behavior can cause any behavior). My issue is with using "unsafe" to mean "watch out, you might be using this incorrectly, but no one even knows the exact rules that you should stick to to make sure your code is correct." Of course, having it be in the "unsafe" part of Rust is better than having it be in safe Rust. But ideally you would be able to look at any part of a Rust program and be able to tell what it does, without having to think in terms of specific compiler optimizations or hardware details. Otherwise formal verification of concurrent algorithms and data structures becomes hopeless.