6 ms·
In the embedded Rust world it is common to explicitly define a custom global allocator and panic handler. The global allocator is even optional although you the
by davidhyde 6y ago
In the embedded Rust world it is common to explicitly define a custom global allocator and panic handler. The global allocator is even optional although you then won't be able to use heap allocated structs like String and Vec. Therefore the Rust compiler does not force you to use the built in allocator or panic handler and you are free to implement them how you choose.
See for alloc: https://docs.rust-embedded.org/book/collections/index.html https://docs.rust-embedded.org/book/collections/index.html
See for panicking: https://docs.rust-embedded.org/book/start/panicking.html https://docs.rust-embedded.org/book/start/panicking.html
- steveklabnik 6y agoThis code is using that allocator, that's part of the issue. He wants there to be no panics, not to have the panics handled in a special way.
- davidhyde 6y agoI see, so anything that can possibly fail should return a result instead of "maybe" panicking as a side effect? So no panics at all in the language? That may adversely affect the ergonomics of the language for user space applications. Perhaps it would be better to build a completely fallible version of the standard library and use linting to enforce no panics.
- steveklabnik 6y agoAt the very least, no panics for allocations. Methods that return Result exist, the issue is that while they do, the panic-ing ones also exist. There are plans to address this, they just haven't been implemented yet.
- davidhyde 6y agoThanks, interesting to hear!
- jononor 6y agoIs a deny(panics) lint-rule feasible, now or in the short term? Something that would make a project fail to compile if anything use in it could panic?
- steveklabnik 6y agoI don't know enough about the specifics to really say. I do know there's interest.
- angry_octet 6y agoIt seems a serious shortcoming if you can't allocate String or Vec using a custom allocator? Presumably you can pass an arena parameter to create the custom allocator? There's plenty of room between <unlimited heap> and <preallocated>, I don't really understand why, e.g., you couldn't have a pool for a particular usage of String, or fixed size objects? Also, introspection to ask which pool an object is allocated on, how much space is available (units for fixed size, largest hole for variable size)? Is it just a syntax choice or is there a rusty reason not to have a thread-local list of allocators?
- steveklabnik 6y agoIt's just time; we have stabilized the interface for the single global allocator, but the more general allocation API is still being worked on. You can do all of these things for your own data structures, but the ones in liballoc shipped without that support, because we had to get Rust 1.0 out the door. Now support is being retrofitted, and that's part of why doing so was okay before; the plan to do so in a reasonable way existed at stabilization time.
- gpm 6y agoThere's nothing special about String other than it's in the standard library. It doesn't even have special cased syntax (&str does have special syntax, it doesn't allocate). String does need to know how to deallocate itself, so the compiler has to know what allocated it. It can be moved between threads, so a thread local allocator doesn't work. If you want a String type which is allocated differently, or which stores a pointer to its deallocate, you can easily implement that as a new type by hand. (The standard library types might some day become generic over allocator, which would allow statically using a different allocator with the same api. The compiler would then force you to keep track of which allocator your string was allocated with).
- scoutt 6y agoAs a C developer for embedded, considering Rust for a long time now, the panic thing is something that bothers me. I don't want/I can't panic. I want to be returned false, null or whatever. Do I have to check if an external crate that I am using would panic? If so, how do I prevent the crate from panicking? From my perspective, Rust is kind-of designed to support code like this (non real Rust code follows): my_struct.do_something() .get_this() .get_that() .as_ref() .as_paper_airplane() .unwrap() What if some of those calls fail? How do I detect an error? Alright, it might panic, but what if I have to keep going forward, even in case of an error, in my embedded application? Should I split the different function calls and check for errors? Kernel development intersects with embedded development in many points. I'm sure I am not the only one with these doubts.
- whb07 6y agoIt would really panic if it ran into an unhandled condition that you explicitly sent it to or left as is. What I mean is pretend you have some external reading/data coming in and you parse it to have the field "name" to always have a value of "scoutt". match data.name { "scoutt" => return True, _ => panic!(), } In that case, because you "know" that the name field cannot be anything but your specific value ,you don't really mind the matching pattern and Rust is satisfied. But then you get a runtime panic! because all of the sudden the value changed to "joe". Long story short is as long as you handle and declare ahead of time the proper fail conditions and paths to take at compile, you really shouldn't come across a panic.
- loeg 6y agoCalls that fail return `Result<OkType, ErrorType>`. Here's something like what `unwrap()` does (actual implementation may have some nuances I didn't capture here): impl<OkType, ErrorType> Result<OkType, ErrorType> { fn unwrap(self) -> OkType { if Ok(x) = self { return x; } panic!("not ok"); } } So, if you don't accept panic, don't call `unwrap()` unless you're very sure that the returned value couldn't fail in the way you're using the API. You could think of `unwrap()` in Rust as semantically similar to `assert(error == 0)` in C. Avoid or use in the same places you would avoid or use that assertion in C. That means you must handle the Err case, often by just returning it to the caller (like C). The ? operator is syntax sugar for this: return if err, or give me the ok value if non-err. fn my_fn() -> Result<(), Error> { // if this failed, returns some Err() let my_x = my_struct.do_something_that_can_fail()?; // ditto let my_y = my_x.something_else_that_can_fail()?; // no failures? Ok Ok(my_y) } Of course, these can be chained with the exact same characteristics: fn my_fn() -> Result<(), Error> { // Equivalent Ok(my_struct.do_something_that_can_fail()? .something_else_that_can_fail()?) }
- finnthehuman 6y agoI don't have a problem with the idea of panic, but the way it's used seems like a wart. In a language with a result type why there are there any cases where the system isn't too broken to return a result, but default to panicking anyway? Thinking about it from the embedded side, my panic is going to tell the failsafe circuitry that the processor can't be trusted. That's too aggressive of an action for any case where we still believe that the processor can return control to a caller that could have a more-graceful error path.