I often find myself writing
def func(a,b):
g = :digraph.new
...
out = some_long_multiline_expression_using_g
:digraph.delete g
out
end
when working with graphs. The distance between `:
digraph.new` and `:digraph.delete` makes it harder to remember to clean up the graph ets tables. The little dance at the end to return a value and also clean up the mutable state feels a bit awkward too. This problem is common when working with mutex, files and other things you need to remember to clean up. Golang has a great solution;
the `defer` statement.
def func(a,b):
g = :digraph.new
defer :digraph.delete g
...
some_long_multiline_expression_using_g
end
This minimizes the distance between declaration and cleanup statement, makes it harder to forget it, and also cleans up the end of the function. If there isn't a `defer` just after some mutable state is created, you immediately know that you need to figure out where the mutable state is cleaned up. If there is a `defer` statement there, you can read the rest of the code without having to think about if every branch has the proper clean-up code in it.
Each `defer` statement pushes a function call onto a stack, with the variable bindings it had when the `defer` statement was reached. When the function returns, the function calls on the stack are executed one by one.