Live data from Hacker News

No-Panic Rust: A Nice Technique for Systems Programming

blog.reverberate.org

81–90 of 143 posts

Re: No-Panic Rust: A Nice Technique for Systems Programming

#81
post #55

Earlier quoted context omitted.

Say a function has some return type Result . If our only error handling mechanism is Err(e) then were restricted to E representing the set of errors due to invalid arguments and state, and the set of errors due to the program itself being implemented incorrectly. In a good software architecture (imo) panics and other hard failure mechanisms are there for splitting E into E1 and E2, where E1 is the set of errors that…

You shouldn't pass invalid values to a function. If a function can return some sensible value for some input, then the input is not invalid - even if the return type is an error by name. Ideally, you can constrain the set of inputs to only valid ones by leveraging types. But if that's not possible and a truly invalid input is passed, then you should panic. At least that's the mental model that Rust is going with. You…

> Ideally, you can constrain the set of inputs to only valid ones by leveraging types. But if that's not possible and a truly invalid input is passed, then you should panic.

But how can the caller know what is "a truly invalid input"? The article has an example: "we unfortunately cannot rely on panic annotations in API documentation to determine a priori whether some Rust code is no-panic or not."

It means that calling a function is like a lottery: some input values may panic and some may not panic. The only way to ensure that it doesn't panic is to test it with all possible input values, but that is impossible for complex functions.

It would be better to always return an error and let the caller decide how to handle it. Many Rust libraries have a policy that if the library panics, then it is a bug in the library. It's sad that the Rust standard library doesn't take the same approach. For println!(), it would mean returning an error instead of panicking.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#82
Why worry about the code size if the code size is up to the library consumer (through their choice of panic handler)? If the consumer worries about code size, then their application has a minimal panic handler. If the consuming application does not have a minimal panic handler, then it must not worry about code size?

Is there some context I'm missing here? Is this to be used from non-Rust applications for example?

Re: No-Panic Rust: A Nice Technique for Systems Programming

#83
post #35

Earlier quoted context omitted.

Sometimes the program is in an invalid state. You don't want to keep running the program. Better to fail spectacularly and clearly then to fail silently and try to hobble along.

The thing with functional programming (specifically, immutable data,) is that as long as the invalid state is immutable, you can just back up to some previous caller, and they can figure out whether to deal with it or whether to reject up the its previous caller. This is why Result (or Maybe, or runExceptT, and so on in other languages) is a perfectly safe way of handling unexpected or invalid data. As long as you en…

> This is why Result (or Maybe, or runExceptT, and so on in other languages) is a perfectly safe way of handling unexpected or invalid data.

They are great for handling expected errors that make sense to handle explicitly.

If you try to wrap up any possible error that could ever happen in them you will generate horrendous code, always having to unwrap things, everything is a Maybe. No thanks.

I know it is tempting to think "I will write the perfect program and handle all possible errors and it will never crash" but that just results in overly complex code that ends up having more bugs and makes debugging harder. Let it crash. At the point where the error happened, don't just kick the bucket down the road. Just log the the problem and call it a day. Exceptions are an amazing tool to have for things that are.. exceptions.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#84
This blog post is very interesting, using Rust’s compiler optimizer as a theorem prover. This makes me wonder: are there any formal specifications on the complexity of this "optimizer as theorem prover"?

Specifically, how does it handle recursion? Consider, for example, the following function, which decrements a number until it reaches zero. At each step, it asserts that the number is nonzero before recursing:

fn recursive_countdown(n: u32) -> u32 { assert!(n > 0, "n should always be positive"); if n == 1 { return 1; } recursive_countdown(n - 1) }

Can the compiler prove that the assertion always holds and possibly optimize it away? Or does the presence of recursion introduce limitations in its ability to reason about the program?

Re: No-Panic Rust: A Nice Technique for Systems Programming

#85

Why worry about the code size if the code size is up to the library consumer (through their choice of panic handler)? If the consumer worries about code size, then their application has a minimal panic handler. If the consuming application does not have a minimal panic handler, then it must not worry about code size? Is there some context I'm missing here? Is this to be used from non-Rust applications for example?

As the author mentions, `panic!` is also not an acceptable failure mode in some applications. If you're developing safety-critical software and a process stopping is part of your risk analysis, many frameworks will ask you about the frequency of that happening. In that analysis, you may be required to set all systematic contributions to that frequency to zero. This happens, for example, if you try to control the associated risk using redundancy. If there is a code path that may panic, you may not be able to do this at all as you maybe just cannot conclude that your code does not panic systematically.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#87
post #29

> Protocol Buffers Instead of serializing data (to disk, not the network), it would be much faster if Rust allowed us to allocate datastructures directly in an mmapped file, and allowed us to read back the data (basically patching the pointers so they become valid if the base address changed).

This is basically what Cap'n Proto does, and it uses offsets instead of pointers so that way the mmapped data can be used as-is.

Good to know, but does Rust have the machinery to make it work with standard Rust data structures?

Re: No-Panic Rust: A Nice Technique for Systems Programming

#88

Earlier quoted context omitted.

An assert is just a fancy `if condition { panic(message) }`. If the optimizer can show that condition is always false, the panic is declared as dead code and eliminated. The post uses that to get the compiler to remove all panics to reduce the binary size. But you can also just check if panic code was generated (or associated code linked in), and if it was then the optimizer wasn't able to show that your assert can't…

Ah, I see what you are saying. Yes, if the optimizer is able to eliminate the postcondition check, I agree that it would constitute a proof that the code upholds the invariant. The big question is how much real-world code the optimizer would be capable of "solving" in this way. I wonder if most algorithms would eventually be solvable if you keep breaking them down into smaller pieces. Or if some would have some step…

Generally you run into the halting problem and whatnot real quick.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#89

Earlier quoted context omitted.

Same, the web view in my Android client crashed after a couple seconds.

I wonder if it's all the Godbolt iframes. Do you have the same problem on other pages, like https://blog.reverberate.org/2025/01/27/an-ode-to-header-fil... ?

Yeah no problem on other pages

Re: No-Panic Rust: A Nice Technique for Systems Programming

#90

This blog post is very interesting, using Rust’s compiler optimizer as a theorem prover. This makes me wonder: are there any formal specifications on the complexity of this "optimizer as theorem prover"? Specifically, how does it handle recursion? Consider, for example, the following function, which decrements a number until it reaches zero. At each step, it asserts that the number is nonzero before recursing: fn rec…

Compilers can typically reason fairly well about tail recursion like this. In this case the compiler cannot remove the assertion because you could pass in 0. But if you change the assert to be a >= 0 (which is vacuously true, as the warning indicates) it will optimize the code to "return 1" and eliminate the recursive call: https://godbolt.org/z/jad3Eh9Pf
Post reply on HN