4 ms·
Can someone tell me what it means to have "no unsafe code"? (I'm a JavaScript developer with very little experience of languages like Rust and C++.)
by callumlocke 11y ago
Can someone tell me what it means to have "no unsafe code"? (I'm a JavaScript developer with very little experience of languages like Rust and C++.)
- DasIch 11y agoRust allows you define blocks of unsafe code in which certain checks aren't enforced by the compiler. In these sections you have pretty much as much freedom as you always do in C.
- ekidd 11y agoIn languages like C and C++, you have precise control over memory allocation and pointers. If you want to say, "My data structure should contain exactly these bytes, and be located here", then you can easily do so. This low-level control makes C and C++ very fast. Similarly, the language does very little "behind your back." It's why most kernels, interpreters, web browsers, compilers and AAA games are still written in a low-level language like C or C++. But this control comes at a price: You need to be very careful. You need to manage memory manually, you need to avoid accidentally writing into memory you don't own, and so on. Overlooking small details results in security bugs. Rust attempts to provide the same low-level control as C and C++, but it adds safeguards which keep you from shooting yourself in the foot. In "safe" mode, all of these safeguards are fully engaged. In "unsafe" mode, Rust allows you to do some sketchy things. The idea is to use as much safe code as you can, and only use a tiny amount of unsafe code if you need to do something Rust can't prove to be safe. For example, there's a great series of blog posts about writing a toy OS kernel in Rust: http://blog.phil-opp.com/ http://blog.phil-opp.com/ The author uses some assembly to set things up, and a tiny amount of "unsafe" Rust to directly access VGA memory. But all the higher level code is safe, which rules out a whole class of bugs. Personally, I've spent a lot time using both C++ and functional languages. And for me, Rust hits a sweet spot: I can get down to the metal when I want, and I can build nice abstractions. And I can write almost all my code in "safe" mode, and not worry about dumb pointer bugs. It's an interesting combination and it makes me want to hack on new things. :-)
- moron4hire 11y agoI wouldn't say the low level control is what makes C fast. Rather, it's the lack of higher level stuff like GC or array bounds checking.
- Retric 11y agoAs far as I know there are not a lot of options, either you explicitly free memory and have low level control (malloc and free etc) or implicitly free memory and use GC. So, I am not sure what you mean?
- zanny 11y agoModern C++ programs should never write a new or delete anymore, except in very particular circumstance. You should always be using make_unique and make_shared for heap allocations and you use shared whenever an object is being passed around and needs to track its owners, unique is for single-usage-instance use cases. Those smart pointers have minimal overhead, deterministic runtime, and have no more overhead than manual implementations of the same mechanisms with raw pointers. That is also how Rust does it - references are smart pointers, so you avoid having a GC.
- Retric 11y agoBeing able to handle a large self-referential data structure automatically is never cheap. So, you need to either have complex GC, a manual approach, or leak memory.
- oldmanjay 11y agoRust's lifetime tracking system is not implemented with smart pointers, although it does facilitate some very smart reference constructs indeed.
- steveklabnik 11y agoTo elaborate a bit, references are "smart pointers" in the sense that they have extra semantics on top of regular pointers, but they also aren't like what most people refer to as smart pointers. Rust's &T (references) are entirely checked at compile time, and generate the exact same code as a regular old C pointer would. No wrappers, extra allocations, reference counts, move/copy/whatever constructors (not that Rust even has those, but are important for C++ smart pointers).
- nbaksalyar 11y agoTo understand unsafe code you need to understand what's safe code and pointers first. Basically, safe code is automatically managed to get rid of memory leaks [0], dangling pointers [1], null pointer dereferencing [2], race conditions [3], and many other memory management bugs. You don't encounter any of these in JavaScript because it's a managed language, meaning there's a garbage collector [4] that looks after all your memory allocations. Contrary to the managed languages, C & C++ are unsafe and "native" (meaning that they're very close to the hardware level) - it's a wild land where you manage memory manually yourself. If you miss a single deallocation, you're left with a memory leak. If you deallocate a memory region twice, you have a double free situation [5]. So you have to be very cautious when writing code in C & C++. There are many techniques to make it easier (e.g. smart pointers [6]), but not all developers use them. Rust takes the middle ground: it combines safety with unsafety by using a know-how affine type system with a borrow checker, which allows values/variables to have only one owner. This system has properties of both managed and unmanaged code. "Unsafe" code in the context of Rust means that you consciously turn off the borrow checker, leaving on your own and managing memory deallocations manually, as in C. That makes it possible to interface your Rust code with the native code, at the cost of making you prone to all errors and bugs that are listed above. So it's a good thing to minimize usage of unsafe code, to allow the Rust compiler to check your code for safety. [0] https://en.wikipedia.org/wiki/Memory_leak https://en.wikipedia.org/wiki/Memory_leak [1] https://en.wikipedia.org/wiki/Dangling_pointer https://en.wikipedia.org/wiki/Dangling_pointer [2] https://en.wikipedia.org/wiki/Null_pointer#Dereferencing https://en.wikipedia.org/wiki/Null_pointer#Dereferencing [3] https://en.wikipedia.org/wiki/Race_condition https://en.wikipedia.org/wiki/Race_condition [4] https://en.wikipedia.org/wiki/Garbage_collection_(computer_science) https://en.wikipedia.org/wiki/Garbage_collection_(computer_s... [5] http://stackoverflow.com/questions/21057393/what-does-double-free-mean http://stackoverflow.com/questions/21057393/what-does-double... [6] https://en.wikipedia.org/wiki/Smart_pointer https://en.wikipedia.org/wiki/Smart_pointer
- easytiger 11y ago> . So you have to be very cautious when writing code in C & C++. There are many techniques to make it easier (e.g. smart pointers [6]), but not all developers use them. Not everyone has security as a requirement. Some people jsut want to write something that is both fast, predicable. Most banks don't make any security demands of internal applications because they are not accessible to the internet. At which point safety is just a way to slow you do.
- Jach 11y agoRust has a particular meaning of 'unsafe': https://doc.rust-lang.org/book/unsafe.html https://doc.rust-lang.org/book/unsafe.html There are just 3 things it allows you to do, but that's all it takes to get the necessary bits of potential-foot-shooting bits out of C/C++. One simple use case for dereferencing a raw pointer is if you're working with an embedded system. You know (through specs) that address 0x00b1 in memory corresponds to a physical button press on the development board, so you write a loop that continuously dereferences this address and does something based on whether the dereferenced value is 0 (pressed) or 1 (unpressed). As far as the source level is concerned, you're just dereferencing a magic address pointing at who knows what value over and over again and never changing that value either. "Unsafe" tells the compiler that you know what you're doing. (And sometimes even in C/C++ you'll need the 'volatile' keyword to keep their compilers from optimizing the dereference to only happen once out of the loop.)
- e12e 11y agoIn addition to what's mentioned below (and you can read on the rust site) -- in a js frame of reference, consider == vs === and/or strict mode vs non-strict. Comparing Rust to C is a bit like comparing js code written in strict mode, using just === for comparison, versus non-strict, use only == - and perhaps always having a custom function that deals with arrays, using eval to marshal objects from strings stored in the array, rather than the object/type features that js provides (especially modern js). It's not a perfect analogy, but perhaps gets a bit of the flavour difference.