But C and C++ don't provide any language level help to programmers who must make their code obey those rules. Rust does. That's the great advance in Rust. The ownership model is explicit and checked.
But C and C++ don't provide any language level help to programmers who must make their code obey those rules. Rust does. That's the great advance in Rust. The ownership model is explicit and checked.
The proof of this is that several core concepts that are considered "safe" have "unsafe" portions that make let work. Thus, there are safe things that rust doesn't consider safe, or that rust cannot infer is safe.
> The proof of this is that several core concepts that
> are considered "safe" have "unsafe" portions
I don't understand this argument. Rust could have built those features (e.g. `Rc`) directly into the compiler itself and it wouldn't have made the language itself any more safe, and it wouldn't have made the safe bits of the language any more or less powerful.In fact, `Rc` was once a first-class part of the language itself, and was indicated by the `@` sigil. The fact that it now lives in the standard library rather than the compiler is because library code is easier to audit for correctness than the compiler internals; to prove that the language is powerful enough to permit user-defined smart pointers and memory management primitives; and to permit alternative implementations of basic language features to be swapped in and out via custom standard libraries (which is way easier to do than forking the compiler).
And C enforces stricter type checking rules than what you need to adhere to in order to write a correct Python program. This is not a bad thing; having an automated assistant that can catch errors as you make them is highly useful. Rust simply pushes this to the domain of memory management and once its rules become more engrained in our development habits, I'm sure it'll be about as painless to deal with than it is to deal with type checking.
I think this is actually a common pattern in many different domains. For example, the OS kernel's virtual memory subsystem does many things with "unsafe" primitives -- it has direct access to page tables and can map anything anywhere -- yet it provides a "safe" abstraction of isolated process address spaces.
The way I think about it is that you have to define basic building blocks somewhere. It's not reasonable to build a static analysis that understands the N different varieties of smart pointers, and refcounting, and dynamically-checked mutability (RefCell), and custom allocators (TypedArena), and all that. It's much more elegant to separate concerns, have only raw pointers and lifetimes/borrowing built-in, and put those pieces together in "blessed" ways with all the unsafe code in one place in the library. If you try to build that understanding into the compiler instead, you're just moving the same unsafe-has-to-be-correct algorithm down one level, and unnecessarily complicating things.
That's also true for any programming language that claims to achieve safety in any sense. At some point you have to have a trusted computing base, whether it's your hardware or the standard library.
In other words, the presence of "unsafe" in the implementations of some things doesn't make Rust unsafe--if Rust is unsafe then so is every other safe language.
Of course, the answer to that is still pretty much exactly what you said: it's true of every programming language that claims to achieve safety in any sense. If Rust is too restrictive then so is every other restricting language.
swsieber, according to says some guy named Gödel, every type system that is sound (and decidable) is not complete. Since decidability is kind of not optional, and most people are not okay with your type system sometimes telling you that something is okay when it's not okay, well, you're gonna have excessive constraints in your language.
I imagine rust would happily extend what it considers safe if it can be determined in an effective way and if it requires additional decoration, doesn't conflict with current syntax.
My point is that rust is a little more strict than C (even correct C). So even if you are a good C programmer who writes without memory leaks, you'll still probably have to battle the compiler for a bit.
Not hating on rust or its abilities - I think it's great.
let x = Box::new(5);
let y = x;
println!("{}", x);
Now C++: unique_ptr<int> x(new int(5));
auto y = std::move(x);
cout << *x << endl;
(I'm being a bit sloppy with namespaces, and both need a main(), but you get the idea)Here, the C++ will compile and (probably) segfault, as x is nullptr after the move. The Rust will fail at compile time, with "use of moved value."
Basically, a (possibly over-)generalization of the situation is "Rust is move by default and captures errors at compile time, C++ is not move by default and cannot statically prevent as many errors as Rust can."