I am not familiar with mechanisms similar to Go's "defer" in other languages. Are there similar mechanisms in other languages?
Go's defer statement schedules a function call (the deferred function) to be run immediately before the function executing the defer returns. It's an unusual but effective way to deal with situations such as resources that must be released regardless of which path a function takes to return. The canonical examples are unlocking a mutex or closing a file.
In Java, you would use a finally
block for that.
Deferring a function like this has two advantages. First, it guarantees that you will never forget to close the file, a mistake that's easy to make if you later edit the function to add a new return path.
Same with finally
.
Second, it means that the close sits near the open, which is much clearer than placing it at the end of the function.
That part is different. In Java, you'd have to place the code at the end. The Go defer statement allows you to declare the clean-up code "inline" instead, which is an interesting twist.
Also, I am assuming that you can use defer
within loops and conditional statements, which would give you kind of a dynamically constructed finally block.
D has a similar construct, the 'scope guard statement', used as
scope (exit) { /* do stuff */ }
scope (success) { }
scope (failure) { }
which run the accompanying block upon any exit, exit without exception and exit with exception respectively, and are equivalent to a try/finally block without the excessive nesting.
I have used a similar mechanism for C++ in the past, for freeing resources of a C library had to use in my project. The class is:
/** A simple class whose job is to mainly help resource cleanup.
*
* The registered callback is called when the current scope is left.
*/
class CallAfterScope
{
public:
/** Constructor.*/
CallAfterScope(const boost::function<void()>& callback)
: m_callback(callback)
{}
/** Destructor: If there is an assigned callback, call it. */
~CallAfterScope()
{
m_callback();
}
private:
boost::function<void()> m_callback;
};
The way I used it was (this is a function that makes use of OpenSSL, if memory serves me):
ErrCode Crypto::GenRsaKeyPair(PrivateKey::SmartPtr pPrivateKey,
PublicKey::SmartPtr pPublicKey,
size_t keyNumBits,
uint32_t pubExp)
{
RSA* pRsa = RSA_new();
if (pRsa == 0)
{
return Err::no_resources;
}
CallAfterScope freeRsa(boost::bind(RSA_free, pRsa));
...
}
The advantage of using this cleanup mechanism is that the the number of lines of code required to perform cleanup drops down to 1 - constructing the cleanup object, and bringing the cleanup scheduling code near the allocation code.
By the way, this was only intended for resources I would allocate and release during a single function call. I implemented a proper wrapper class for anything that I needed to keep around and operate on for a longer duration (such as the PrivateKey and PublicKey classes that I pass to this function). The idea was to minimize the amount of wrapper classes I would need to implement.
TL;DR: In a way, defer is a very, very old ASM trick finally being put to use in a higher level language.
Not a useful answer in any way, but possibly interesting: it just so happens I posted an anecdote on the Go mailing list today on how you can do this in Z80 ASM:
In Z80, you run a procedure with CALL label. Procedures end with RET. I'll quote from Sean McLaughlin's excellent tutorial:
"To understand CALL fully, you need to be aware of a specialized register called the program counter PC. The program counter holds the address of the currently executing instruction. What happens during CALL is that the current program counter value is pushed onto the stack, then a transfer to the label is done. RET pops the top stack value into the program counter."
.. so what I figured was that there was nothing stopping you from PUSH-ing a label for another procedure on the stack (or more of them, if you want). If you'd then call RET you'd jump to the other procedure first, which would of course end with a RET itself, finishing everything properly.
I never found a use for it though, the needs of TI-83+ programs aren't that complicated :P. The more standard control structures were always more appropriate for my needs.
Turns out this is fairly similar to how Go's defer works under the hood. Cox even mentions the following:
"All three are also the kinds of tricks that were commonplace in the early days of Unix, since it had been written in assembly. For example, the original fork system call handler distinguished parent from child by changing the return address just as jmpdefer does. In modern Unix, the fork system call returns the new process id in the parent but returns zero in the child. In the early versions, including Sixth Edition, fork returns the new process id in both, but the child returned normally while the parent returned to one instruction past the usual return address. Thus the instruction after invoking the fork system call needed to be an unconditional jump to the child-specific code."
Using the same system as @Dysaster I implemented what I called a DelayedAction
mechanism in Python, and used it mainly for DelayedLog
.
The idea is that in Python when an exception is thrown, you have the callstack, but you don't have the actual arguments (their values), thus I guarded a couple of critical functions in the following manner:
def mayFail(arg0, arg1, arg2):
delayed = DelayedLog('mayFail - ' + str(arg0) + str(arg1) + str(arg2))
// do stuff
delayed.cancel()
At worse, I forget to cancel before an early return and do log, but it's usually easy to clean-up.