5 ms·
As someone who's been using (and really liking) rust for about 6 months, there are two things in this article which are, I'd say, 'common misconceptions' about
by shadowmint 12y ago
As someone who's been using (and really liking) rust for about 6 months, there are two things in this article which are, I'd say, 'common misconceptions' about rust:
One of the coolest features of Rust is how it automatically manages
resources for you, while still guaranteeing both safety
(no segfaults) and high performance.
In rust there are two types of code. 'safe' and 'unsafe'. The above is only true if your entire code path contains only safe code.
NOT, if you only write safe code.
That is, if you write entirely 100% safe code, and use some library that uses 'unsafe' code at a low level (this is very common; for example, an C binding or memory optimization), then rust does NOT guarantee safety.
Furthermore, there is no way to know if your code path includes unsafe code.
Rust is relatively safe; it's just not totally safe. Using rust does a reasonable job of protecting you from segfaults most of the time; but it's not a silver bullet.
As soon as the program stops using the resource, its cleanup logic gets
invoked.
...
Because only one scope owns an object at a time, you can tell just by
looking at it which objects will be destroyed when it's done executing.
This isn't always necessarily true.
Rust uses 'drop flags', which are extra bytes at the end of struct instances in memroy, to track objects and keep meta information about them to determine if they should be dropped.
At the end of scope when the drop checker runs it checks against these drop flags to determine if an object should be dropped or not.
(For example, if a closure captures a variable it may no be dropped at the end of the scope it would normally have been dropped in).
There seems to be this myth that resource deallocation in rust is magically determined at compile time and the has 'zero cost'; it's simply not true.
There is a runtime cost to the drop checker; it's not particularly large, but it's certainly not just a sequence of drop operations.
Don't get me wrong; I really enjoy rust, and I like it a lot. ...but those two ideas pop up repeated in discussions about it, and they're not exactly correct.
- wycats 12y ago> In rust there are two types of code. 'safe' and 'unsafe'. The above is only true if your entire code path contains only safe code. I think this is actually a misconception. In every high-level language (Ruby, Python, etc.) there are APIs for interacting with low-level code. These APIs (C bindings and FFI) are unsafe, and are in the path of virtually all high-level code. It is the responsibility of somebody implementing a C binding for Ruby to ensure that the publicly exposed API is safe. If you use `nokogiri` in Ruby and get a segfault, that is a bug in nokogiri. It is not an indication that Ruby is unsafe. Similarly, the "safe" dialect of Rust is Rust. Rust provides a low-level binding to unsafe code via the unsafe dialect that is philosophically equivalent to the FFI API or C bindings in Ruby. If somebody uses the low-level binding and exposes a Rust library that segfaults, there is a bug in that binding, full stop. I think this is very important. If you use regular Rust code with the expectation that "anyone in your path may cause you to segfault", something has gone very, very awry in the ecosystem. This is not an expectation in other high-level languages when people write low-level libraries with unsafe code in them, and it should not be an expectation in Rust. > Rust uses 'drop flags', which are extra bytes at the end of struct instances in memroy, to track objects and keep meta information about them to determine if they should be dropped This is in the process of being eliminated (see https://github.com/rust-lang/rfcs/pull/320 https://github.com/rust-lang/rfcs/pull/320). I didn't mention it because it's runtime overhead that will not be present shortly, and certainly by the time 1.0 is reached later this year.
- shadowmint 12y ago> If you use `nokogiri` in Ruby and get a segfault, that is a bug in nokogiri. It is not an indication that Ruby is unsafe. Rust has a strict definition of safety; not all rust code for fills that guarantee. We're not talking fast and loose here. These are absolute definitions. You can write safe code that crashes in rust. That absolutely violates the safety guarantee whatever the reason for it. > This is in the process of being eliminated No it's not. Keep dynamic drop semantics, by having each function maintain a (potentially empty) set of auto-injected boolean flags for the drop obligations for the function that need to be tracked dynamically (which we will call "dynamic drop obligations"). What's happening is some of the run time overhead is being reduced.
- wycats 12y ago> You can write safe code that crashes in rust. That absolutely violates the safety guarantee whatever the reason for it. You can write Ruby code that calls into unsafe C code and SEGVs. This is a bug in the C code you called. It should have exposed a safe interface. You can write Rust code that calls into clearly delineated unsafe code and SEGVs. This is a bug in the unsafe code you called. It should have exposed a safe interface. Anything to the contrary is a misunderstanding of the purpose and role of unsafe code in Rust, and endangers the entire ecosystem, just as it would endanger the Ruby ecosystem if it were seen as normal for C extensions to SEGV the safe Ruby process.
- nwmcsween 12y ago'Unsafe' is a bad term, effect is much better and it is most definitely a rust issue. If the language doesn't have a way of dealing with effects it won't be able to handle them. Rust is honestly a more safe c++ and in my opinion not an alternative for c.
- wycats 12y agoI don't know what this means. I stand by my upstream comment.
- pcwalton 12y ago> That is, if you write entirely 100% safe code, and use some library that uses 'unsafe' code at a low level (this is very common; for example, an C binding or memory optimization), then rust does NOT guarantee safety. What do you consider a "guarantee"? Do you consider pure JavaScript to "guarantee" safety, even though there have been exploitable bugs in the JIT and interpreter? Do you consider pure-computation, non-allocating Rust to be safe, even though LLVM may contain codegen bugs that allow for undefined behavior? Do you consider seccomp-isolated code to be safe, even though there have been, and will likely be in the future, kernel bugs that allow sandboxed process to escape? The point is that instead of talking about "100% safe", which is never the case in the real world, I think it's better to talk about trusted computing bases. That is, instead of saying "X is safe" or "X is unsafe", we talk about what effect X has on the memory-unsafe surface area of a program. Rust's goal is to reduce the trusted computing base of an application written in it to the hardware, compiler, unsafe blocks, and type system. This gives us essentially the safety properties of "managed languages" (except I don't like that term because it tends to imply garbage collection and lack of fine-grained control over memory, which don't apply to Rust). A specific example I like to give: Sure, we could hardwire (for instance) Vec into the language, and therefore reduce the number of lines of unsafe code in the libraries. But doing so would just be moving the unsafe code from the unsafe blocks in the libraries to the compiler itself. There would be no net gain in safety from it—compiler code can have bugs just as library code can—and there would be a decrease in maintainability and flexibility. You can think of Rust's safety properties as establishing a type of sandbox if you'd like. All sandboxes have trusted computing bases, and Rust's compile-time sandbox is no exception. But "safety" as applied to a sandbox still has an important meaning. Chromium/Firefox OS's sandbox, for example, is a safe sandbox, even though its security depends on strong assumptions about the trustworthiness of the OS kernel and the IPC layer between the trusted and untrusted processes. > There is a runtime cost to the drop checker; it's not particularly large, but it's certainly not just a sequence of drop operations. After the drop optimizations are done, this will only be true if you conditionally move an object on one or more branches. It's already true today if the object gets SROA'd on the stack, as LLVM can then optimize out the drop flags. We've talked about adding a lint so the compiler can optionally warn and allow you to fix it if this performance cost is a concern to you. (It's a very minor cost—one test and branch on a stack byte, and again only if the object is conditionally moved.) Note that C++ move semantics incurs essentially the same cost.