5 ms·
I disagree. Just as C++ and Rust conceive of "plain old data" (POD) as data that basically has no surprising behaviors on cleanup (probably butchered that expla
by vacuity 2y ago
I disagree. Just as C++ and Rust conceive of "plain old data" (POD) as data that basically has no surprising behaviors on cleanup (probably butchered that explanation), I think of libraries as "plain old code". Unlike services, libraries are part of the address space and should passively serve the main executable portion. That's why they are libraries specifically. A library should, if it detects an error, tell the main executable and then it is up to the main executable to do the responsible thing and address the error seriously. Needless to say, I don't like glibc-style "libraries". Doing too much in the background, in the same address space, no less. A library should be a nice, isolated unit that a programmer chooses to add into their executable at will. My concern is that composability and modularity aren't respected enough.
- GuB-42 2y agoI consider a panic to be equivalent to a segfault. It is a bug, either in the library itself, or unproper usage, and the system just stopped you from doing further damage. The only reasonable thing to do in this case is to fix the bug. Imagine you are catching the exception. What are you going to do next? From now on, anything can break, and how do you hope recovering if you couldn't do it right in the first place (that's what caused the panic)? You can have a panic handler, in the same way that you can trap SIGSEGV, for some debugging, but that's about it. If a crash is really problematic, use some process wrapper, and maybe a watchdog. Libraries don't work like that for performance and flexibility reasons, they share address space, but the downside is that if they crash, they take everything else with it.
- vacuity 2y agoIndeed. It's in the name: libraries are there to be browsed, while services wait for customers to call on them (and do management and other things in the meantime). This should be understood among the developers of applications, libraries, and services, that libaries are functional add-ons while services are separate agents. A library has its expertise and should isolate bubble up application errors (to be fixed by the application) and environmental errors (can't really be fixed by anyone, but the application should decide how to proceed). If a library has internal errors, how is the library itself or the application supposed to fix it? It's like position-independent code: if its basic assumptions are met, it should be plug-in-play anywhere without complaint or knowledge.
- int_19h 2y agoThat is exactly what panics do in Rust. The difference between Result<T,E> and a panic is basically two-fold: 1. The owner of the process (whoever is compiling the binary) - not the library! - gets to decide whether panics immediately abort or try to unwind in a way that can be handled. 2. A panic is never expected (i.e. it always indicates a bug in the code rather than invalid input or other expected failure conditions), so it's optimized for the success scenario both in terms of syntax and in terms of runtime cost. In practice, it means that syntactically the panic always auto-propagates (whereas you need `try` etc with Result); and the code generated by compiler is zero-cost wrt panics if one never happens, but the unwinding is very slow if a panic does happen.
- vacuity 2y agoWhile panics can be made to unwind and be caught, at that point the different error handling methods are really abort/Result bubbling/Result bubbling but cooler, and I want the last one to be packaged up nicer than "unwinding panic" is today. Stack unwinding should be orthogonal. And I think Result bubbling the boilerplate way is good unless performance is paramount. Keeps the happy and error paths abundantly clear to the developer. I don't know the details of C++'s zero-cost exceptions, but Rust's certainly are not.
- int_19h 2y agoCan you clarify what you mean by "packaged up nicer"? Given that this is a feature that should be used very sparingly, and also one that is very apt to be misused (as experience with exceptions in other languages demonstrates), I would argue that lack of syntactic sugar for it is a good thing. But I'm willing to consider arguments to the contrary, yet the existing API seems broadly fine to me? How would you change it? As far as cost, it depends on the arch and its ABI, but on x64 they use something called "unwind tables", which is basically a structure that lists all cleanup code that needs to be run for unwinding given a range of addresses inside a function. Such tables can be produced entirely at compile time, and they only need to be checked during unwinding (i.e. if there's a panic), so on the success path you pay no perf penalty. They are not entirely free in that they do make your binary larger, but speed shouldn't be affected.
- throwaway17_17 2y agoI'm absolutely sure that this is the clearest statement of how I view libraries I've ever read. I am not actually certain I would have phrased it this well. So I'm commenting to save it in my comments thread.