Also I'm not sure the cognitive overhead is really that big. The compiler helps a lot with its useful error messages.
Also I'm not sure the cognitive overhead is really that big. The compiler helps a lot with its useful error messages.
It’s pretty common to need to interact with existing APIs or libraries that only have a c interface.
Fortunately, rust is good at that.
Unfortunately, it’s impossible to do without unsafe code.
You can wrap libraries in safe wrappers, or if you’re lucky someone has a wrapper you can use…
…but I’ve heard it several times for this reason, especially in shops that have existing internal code bases (Ie. 0% chance of an existing safe wrapper) and want to incrementally adopt rust.
Never heard someone say it’s because of perf tho; that sounds like a strawman argument to me; if your code is seriously too slow because of the bounds checking you’re doing something crazy and probably want to be using a gpu instead.
It’s usually io bound, and unsafe code doesn’t fix that.
As someone trying very hard to love Rust this is just simply not the case. It takes the shortest path to most answers. The most trivial example where the compiler becomes less helpful is a self-balancing binary tree. It will constantly suggest explicit lifetimes and other magic when in reality you probably want `Box<Rc<..>>`. It will suggest Boxing for recursive types...but that's about the end of it. In many cases you're better off knowing what to do. But the problem is knowing what to do requires you to have done what you need...and hence the Rust Ouroboros is born.
The nice thing about unsafe code (C, for example) is the cognitive overhead is initially very low. That allows you to get an idea down and then worry about stuff later. Of course, if you have a gun to your head from management you never get to the "worry about stuff later" stage and introduce all sorts of nasty bugs. Rust frontloads all of this making it sometimes very difficult to use without having everything already thought out way ahead of time. Both a benefit and a curse.
There’s only so many variations that work for something like trees (especially with doubly linked nodes) in any language, without either inherently unsafe lifetimes (because the particular language can’t express them as part of the API) or some kind of indirection (such as ECS style indices). Or garbage collection or ref counting, but one probably uses Rust to be able to control that kind of overhead instead of having to use whatever the language creators picked.
If you want to learn about this, instead of using a ‘blessed’ implementation, read “too many linked lists” https://rust-unofficial.github.io/too-many-lists/.
As for the front-loading comment: yes, Rust requires you to get some things right from the start, particularly ownership and lifetimes. If you want to work in Rust like in a scripting language, you can just use Box, Rc and clone() everywhere. But getting it right without those might require a significantly different API. Which isn’t that much different with your rough C implementation. To get any kind of safe API there will require just as many changes (if not more).
If you can provide examples of cases like these, please file a ticket in the issue tracker. Some suggestions have to be overly cautious in order to not lead people astray, so having examples of common (or uncommon!) things people try that could use with some "human touch" in what direction they should take instead is very useful and welcome.
I think now that too many lists is part of the book, maybe the compiler can link to that in some cases, hah.
A lot of the cases I've seen so far require some kind of global analysis, that we don't have today. But if we can have some kind of local analysis that will be reliable for a subset of cases, I'd jump at the opportunity to add it.
> I think now that too many lists is part of the book, maybe the compiler can link to that in some cases, hah.
That's not a bad idea, we already link to the book when it seems appropriate.
Even heap allocations like `Box` are still just pointers, that have destructors that run when they fall out of scope, but access is just a pointer dereference, the same as you could do with unsafe.
Look at the Firecracker codebase. There are a lot of unsafe calls into libc.
There is also a runtime reference counter which takes up cycles since it has to operate at run time.
I'm not trying to invalidate all claims that unsafe is necessary, nor even that there are cases where unsafe is quite helpful for performance. It's just that a little unsafe used deliberately and thoughtfully can go a long way, and accomplish those goals in a largely safe codebase.
Re: overhead—I think the compiler helps a ton here, but I do think that it makes a lot of memory-related concerns explicit where they are usually implicit, and dealing with lifetimes can be quite burdensome. Now: I also think that those concerns still exist when you're using other systems-level languages, and that the tradeoff therefore often ends up looking like "Deal with it up front, or deal with it on hard mode later."
- From a language point of view, the syntax for dereferencing pointers in rust is awful. I don’t mind the unsafe keyword. But in rust you can’t do a->b. You need to write (*a).b. And that gets increasingly awful as you have more complex pointer expressions. Unsafe code in rust looks significantly uglier than the equivalent C.
- The Rust community - particularly on Reddit - seems to get very snide annd condescending about programmers using any amount of unsafe in their rust code. Even when it’s totally necessary. I’m not convinced the community will is there to fix rust’s bad pointer syntax, or other missteps with unsafe. Apparently having unreadable unsafe code is my atonement for wanting high performance code. Never mind that the harder my code is to read, the more likely I am to make mistakes. And in exactly the part of my codebase where bugs would be the most damaging to safety! Argh.
I love rust. I love the fresh ideas it’s brought to programming as a whole. But I can’t wait for some other, newer languages to iterate on these features & the language syntax some more. It’s not the top of the mountain.
For what is worth, I think that we'll add that at some point.
Cargo stores packages from both sub-communities and we fight over the heart of rust. - And sometimes to our collective detriment, like what happened to actix.
Also: agreed re: syntax.
> But I can’t wait for some other, newer languages to iterate on these features & the language syntax some more. It’s not the top of the mountain.
YEP. That's exactly what I was getting at in my callout at the top of the piece. First word, not the last.
It primarily comes up when you're 1) interfacing with hardware 2) interfacing with C APIs 3) doing something weird with pointers.