I really wish Rust tutorials would include this information, and people wouldn't need to ask the same question again and again and again. This question is asked on this forum about two dozed times per week.
I know, I know, math. Math is scary, if we even mention that word in a tutorial people would run away screaming, but still… it's tiring to explain the same thing again and again and again.
Basically: it's impossible to answer any “interesting” question about some random syntactically correct program. Is this program which would, eventually, stop? No way to know. Is this program adding two numbers? Who knows. Nothing (except some trivial properties) can be gleaned from the program source.
And that's not “we don't have money to make it happen”. It's quite literally impossible.
And yet… people usually want to know if their program is “correct” (for some definition of “correct”) and negative answer “sorry, we couldn't do that” is usually not considered an adequate answer. Yes, that same infamous: In theory, theory and practice are the same. In practice, they are not.
Rust developers are practical guys thus they split this impossible to solve problem in two, like Alexader the Great did many years ago. Instead of picking one option: reject useful programs which may or may not be correct (like most high-level languages do) or accepting invalid program (like C, C++, or Zig are doing) Rust gives you the choice:
- In “normal”, “safe” Rust the compiler is in charge and compiler ensures that your program is “correct” (for some definitions of “correct”). But that, of course, means that it would be rejecting some “correct” programs (sorry, no way to avoid that). Like C# or Java only with more safety guarantees.
- If you use that magical word
unsafe
, then, oh well, you probably know what you are doing: Rust gives you the means to write anything at all (like C, C++ or Zig)… but with great power come great responsibilities: now it's your obligation to ensure that program is correct. If you fail… not only the code you wrote but also anything outside of your code, maybe millions of lines of code removed from your tiny transgression… may misbehave.
And that is where the issue with read
comes from. It's safe trait which means that anyone can implement it incorrectly. Without help from unsafe
code you couldn't overflow the buffer (compiler would look after that), but you can return some random gibberish as a return value (compiler doesn't know that this number is, somehow, related to amount of data written into buffer and couldn't check). That, in turn, means if you would be writing unsafe
code which deals with Read
trait then it couldn't rely on the fact that read
returns correct value. If would need to do it's own sanity checking.
That's it.
Without knowing that dual nature of Rust the whole description sounds incredibly strange and hard to understand.
But if you know about these two “dialects” of Rust then it, suddenly, makes perfect sense.