Hacker News new | ask | show | jobs
by Manishearth 3532 days ago
> . Is it to be avoided if at all possible, or should I go there any time the 'safe' part of the language is making it difficult to express what I want?

The main reasons to use unsafe code are when you're doing FFI and have to regrettably talk to C/++ libraries, or when designing new abstractions with a safe API boundary. It's tricky to ensure that the former is safe since you eventually have to trust C++ (but then, that's not Rust's fault). It's not hard to ensure that the latter is safe. Looking at a page of code and ensuring that it can't cause segfaults is a much easier task than doing it for the entire codebase.

This is almost all the unsafe code out there. There's a bit of it used for doing manual optimizations. When Rust doesn't let you do what you want, often there are abstractions like RefCell that have a small cost that you can use (and they contribute to the overall safety). In case this happens in performance critical code, you can use unsafe again, but this is very rare.

In Servo, for example, almost all of the unsafe code is of the first two kinds. I've been hacking on Servo for years and didn't write much unsafe code at all -- when I did, it had to do with talking to Spidermonkey, and even that was pretty rare. More recently I'm working on integrating Servo's style system into Firefox (which is C++), and only now have I been regularly writing unsafe code. Even for this project the unsafe code I'm writing abstracts away the inherent unsafety of Firefox's C++ so that others can talk to Firefox with safe Rust code.

But many projects have no unsafe code at all. It's not that common to have unsafe code.

> it was difficult for me to find performance characteristics of the underlying abstractions and std library (for example, are algebraic data structures just tagged unions or does the compiler do more fancy things with them? What about iterators?).

Note that a C++ book won't help here for C++ too. What is a switch compiled down to? Does it use a jump table? :)

But yeah, it would be nice to have a thing for this. I don't think it belongs in the official book, but it should exist :)

ADTs are tagged unions. When non-nullable pointers are involved sometimes the tag is stored as a null pointer (e.g. `Option<Box<Foo>>` is a single pointer, and is None when null. Aside from that, nothing fancy.

Iterators compile down to the equivalent for loops. I can't think of any stdlib iterator which implicitly allocates; they all operate on the stack. In general these are just zero-cost abstractions, they will compile down the the code you would have written with manual loops. This is a recurring theme with the stdlib and even crates from the ecosystem. "extra" costs for abstractions are eschewed in Rust and will often be documented when they exist. So as a rule of thumb assuming that a random abstraction doesn't have an overhead unless explicitly mentioned is good.