Proposal: Golang's defer statement for cleanup of side-effects

115 views
Skip to first unread message

Filip Haglund

unread,
Aug 5, 2016, 1:39:39 PM8/5/16
to elixir-lang-core
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.

Michał Muskała

unread,
Aug 5, 2016, 1:57:48 PM8/5/16
to elixir-l...@googlegroups.com
This can be easily achieved with a helper higher order function:

def with_graph(opts // [], fun) do
g = :digraph.new(opts)
try do
fun.(g)
after
:digraph.delete(g)
end
end

And, later in the code you can call:

with_digraph(fn graph ->
# some operations
end)

This guarantees proper cleanup, and doesn’t require any additions to the language. It also allows you to separate all the lifetime code from the algorithm. It’s a pretty common pattern for guaranteed cleanup when you have higher order functions.

Michał.
> --
> You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/2c0d8195-ec44-4112-a0c1-2f5c5f3905b2%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

signature.asc

Paul Clegg

unread,
Aug 5, 2016, 2:51:25 PM8/5/16
to elixir-l...@googlegroups.com
Why not just use try/after?

...Paul



--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages