https://github.com/pacman82/strong-function
https://github.com/pacman82/strong-function
Last synced: 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/pacman82/strong-function
- Owner: pacman82
- Created: 2024-04-16T16:36:48.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2024-05-02T21:19:40.000Z (about 1 year ago)
- Last Synced: 2025-02-01T20:14:30.024Z (4 months ago)
- Language: Rust
- Size: 3.91 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: Readme.md
Awesome Lists containing this project
README
# Strong exception safe functions
An trait for functions offering strong exception safety guarantees explicitly and utility for executing them one after another in an exception safe manner.
## Motivation
While Rust does not have exceptions, as far as I can tell the terminology of exception safety (https://en.wikipedia.org/wiki/Exception_safety) is still used. It is of course entirely possible to write functions offering strong exception safety in Rust, following this rough pattern:
```rust
fn strong(&mut world) -> Result<(), Error>{
// May fail, but only changes temporary state
let tmp = may_fail()?;// Commit. The second part changes application state, but can never fail
world.change(tmp);
Ok(())
}
```A problem arises, though if we want to execute two exception safe functions one after each other in an exception safe way.
```rust
// If this line fails, all is good. We did not change application state in case of an error, because
// `strong` is exception safe.
strong(&mut world)?;
// Oh no, if this line fails, we already changed `world` in the first line. The fact that `strong2`
// is execption safe does not help much.
strong2(&mut world)?;
```Common occurrences of this problem are calling a function in a loop, or calling a list of handlers in an observer pattern. By making the `may fail` and `commit` part of a function explict in this trait you gain utility for chaining them together in manner which maintains strong exception safety.
```rust
struct Strong<'a> {
arg: &'a mut Arg
}
impl<'a> Invocation for Strong<'a> {
type Error = Error;
type Output = ();
type IntermediateState = Tmp;
fn may_fail(&self) -> Result {
may_fail()
}
fn commit(self, tmp: Tmp) -> () {
self.world.change(tmp)
}
}// ...snip...
(Strong { arg: a}, Strong { arg: b}).execute();
```