is a design pattern used when dealing with relatively complicated functions with multiple (logical) points of exit, and you want to make sure that certain cleanup actions always occur. If multiple return statements exist; it is highly likely that one of these will forget to do whatever cleanup is required. Many people dislike GoTo
statements (to a "cleanup" block at the end); and the ArrowAntiPattern
This is especially applicable in languages without ExceptionHandling
and/or constructs like UnwindProtect
or "always" blocks. In languages without GarbageCollection
, this is especially important.
The pattern is as follows:
The function is broken up into two functions--one (the wrapper) is externally visible and is what client code calls. The other is usually only internally visible (static, private, lexically nested, etc.). The wrapper function does the following:
- Performs most or all resource acquisition (for resources that require explicit deallocation)
- May verify preconditions on arguments or initial system state
- Calls the "wrapped" function
- Regardless of the return state of the "wrapped" function, deallocates the resources.
- Returns the return value to the caller.
- Optionally, might check postconditions and/or do other debugging-useful things (log errors and the like).
The wrapped function does the dirty work of the computation. Since it is freed from having to worry about resource allocation and de-allocation, it can have multiple exit points without the programmer having to worry about freeing all resources correctly.
is useful for other things besides resource management:
- Extending the interface of a function without breaking legacy code--especially in languages that don't support overloading or DefaultArgument?s
- Providing other debug semantics. If I have to write a RecursiveFunction (especially one not tail-recursive), I'll often write a (non-recursive) wrapper function which calls a (recursive) wrapped function, and add a "recursion count" parameter to the wrapped function. Each layer of recursion increments it by one; if it reaches a certain value I can terminate the recursion. (Especially useful in environments where StackOverflow isn't reliably detectable).
Plus, if you add state to your FunctionWrapper
and turn it from a function to a full-fledged object, you have the HandleBodyPattern