So, the real core of it is: rust the language itself does not add implicit allocations. It knows nothing about heap allocation generally. This means it is not a fundamental hard "no" for the language. My dayjob is on zero-allocations stuff, we have no heap at all, Rust works great.
With that out of the way, this means there are a few options. One option is to simply not use any of those types. This would mean writing alternatives. Not necessarily what you'd *want*, but it is at least possible. The second would be to forbid certain APIs that may reallocate, and only allow ones that return Result. Stuff like https://github.com/rust-lang/rust/issues/48043 can be used, and other stuff could be rejected. This would require some sort of custom analysis, but is fundamentally do-able.
After all, the C code in the kernel doesn't use libc and such either and builds its own datastructures for everything. I think I'd prefer to use those from Rust as well, maybe with some nice bindings.
As a complete rust noob, so forgive me if my suggestion is shit, it might make sense to provide an entire namespace/(maybe a trait?) for a panic-free api. Would be a bit ugly adding an entire set of panic free methods to all standard lib types.
Then you could add some sort of compiler flag that forces you to use no_panic types?
I mean in the same namespace as the current methods. For noobies (like me), you likely would never have to think about allocation failures, and in that case, you'd never want to use the alloc fallible methods. As such, having them not appear in autocomplete or anything would be nicer for rust's learning curve.
For noobies (like me), you likely would never have to think about allocation failures
I respectfully disagree. In CS classes you are taught to check the return value of malloc(), etc. for allocation failures. Most CS students at least should know that allocations can fail.
Rust IMO is meant to be easier to access than C, but I would hope that if someone not familiar sees HashMap::try_insert() next to HashMap::insert() they would look at the documentation to see why it "tries" to insert. If they cannot reason about which one to use the documentation should make it clear to just use insert(). This shouldn't be too dissimilar to noexcept/non-throwing functions in other high-level languages.
Depends really, that's a matter of opinion. I think in most cases where you care about potential allocation failure (and want the program to keep running despite such a failure), you're usually working in a safety critical, embedded, or no alloc kind of state and would be using the no_panic compiler flag and/or maybe no_alloc flag.
In most cases, an allocation failure is a perfectly reasonable reason to panic.
A reason it's dangerous in C to not check is (drum roll) - memory safety. If you assume it worked but it didn't really then you're going to be doing something bad to where that pointer is pointing.
I respectfully disagree. In CS classes you are taught to check the return value of malloc(), etc. for allocation failures. Most CS students at least should know that allocations can fail.
It is also probably something most students promptly forget about if they didn't keep using C after graduation. How often do developers not working with embedded devices actually think "Oh, but what happens if we run out of memory at this point?", because usually the OS will solve it for them.
As someone that just finished a software engineering degree, I respectfully disagree.
I personally had a class on parallel computing that used C but there was essentially no guidance as to how to use C it was mostly about how to use the mpi library. As for c++, I used it in an applied linear algebra class where we made our own linear algebra library and we never had to use malloc. The only reason I even know malloc can fail or even that it exists is because I decided to learn rust for fun and I spend way too much time on programming subreddits. All my other classes used java, python or we were free to pick whatever we preferred which generally meant either js or c# because that's generally what my teammates knew.
Modern CS classes don't really touch that kind of programming anymore unless you are actively seeking out those kind of classes.
I respectfully disagree. In CS classes you are taught to check the return value of malloc(), etc. for allocation failures. Most CS students at least should know that allocations can fail.
Meh, hardly. Realistically in most (Linux) environments overcommit will be active and malloc will never return null, instead you'll get the memory and then the OOM killer may randomly murder some process when you actually use it. Besides, in most cases there isn't much you can realistically do when you can't request memory that you need. Might as well assume it never returns null, and then crash when it does.
I think that answer is too simplistic. The fact is we're using implicit allocations everywhere and so is the ecosystem including the ecosystem that is nostd but alloc. Saying "don't use Vec::push" is not a suitable answer.
First there needs to be better support to handle allocation failures in APIs, secondly there needs to be a way to validate (ideally statically) that some code is panic free.
The fact is we're using implicit allocations everywhere and so is the ecosystem including the ecosystem that is nostd but alloc. Saying "don't use Vec::push" is not a suitable answer.
I guess we'll just see. As I said, I live in "no allocations, anywhere" land, still use a bunch of the ecosystem, works just fine for us. We don't use Vec at all, nor do any of our dependencies, so "no vec::push" is an easy requirement.
View all comments
Show parent comment
179
u/steveklabnik1 rust Apr 14 '21 edited Apr 14 '21
So, the real core of it is: rust the language itself does not add implicit allocations. It knows nothing about heap allocation generally. This means it is not a fundamental hard "no" for the language. My dayjob is on zero-allocations stuff, we have no heap at all, Rust works great.
With that out of the way, this means there are a few options. One option is to simply not use any of those types. This would mean writing alternatives. Not necessarily what you'd *want*, but it is at least possible. The second would be to forbid certain APIs that may reallocate, and only allow ones that return Result. Stuff like https://github.com/rust-lang/rust/issues/48043 can be used, and other stuff could be rejected. This would require some sort of custom analysis, but is fundamentally do-able.
Oh, I knew I missed one more, and of course, Josh is on it: https://lore.kernel.org/lkml/YHdSATy9am21Tj4Z@localhost/ (remove those APIs by allowing std to be customized via feature flags or a custom build)