2.4 KiB
defer in Rust
After a Hacker News discussion about implementing Go's defer keyword in C++,
I stumbled upon this comment
and more specifically this response to it by "Occivink":
There's plenty of one-time cases where you don't want to declare an entire class but still enjoy scope-based functions.
Specificall the "don't want to declare an entire class" suggests that languages
like C++ have high friction for explaining your desired invariant (cleanup is
run when $thing is destroyed) to the compiler.
It seems like most languages either hand-wave this away (cough Java cough)
or use what seems like a workaround (defer).
Rust has the so-called Drop trait, which is a typeclass that contains a single
method with no return value that is run when a variable is dropped (i.e. goes out
of scope).
This works fine for most general cases - i.e. closing file handlers - but can
get complicated if other use-cases of defer are considered:
- returning an error-value by mutating a reference in the enclosing scope (oh boy)
- deferring a decision about when/whether to run cleanup to the caller
While thinking about how to do this with the Drop trait I realised that defer
can actually be trivially implemented in Rust, using Drop.
A simple implementation of defer can be seen in defer.rs,
an implementation using shared mutable state for error returns is in the file
defer-with-error.rs and an implementation that
allows cleanup to be cancelled (don't actually do this, it leaks a pointer)
is in undefer.rs.
Whether any of this is actually useful is not up to me to decide. I haven't actually had a real-life need for this.
You can run the examples with cargo run --example defer, etc.
Notes
Dropis not guaranteed to run in case of panics or program aborts, if you need support for that check out scopeguardundefercould be implemented safely by, for example, carrying a boolean that by default causes execution to happen but can be flipped to disable it