Last active
August 5, 2018 01:22
-
-
Save TotalVerb/ab823503cd6d282c0ba273d2b85125f1 to your computer and use it in GitHub Desktop.
Go's defer with Julia macros
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using MacroTools | |
symbolsof(ex::Symbol) = [ex] | |
symbolsof(ex::Expr) = ex.head == :line ? Symbol[] : vcat([symbolsof(x) for x in ex.args]...) | |
symbolsof(ex) = Symbol[] | |
reflect(ex) = Expr(:(=), ex, ex) | |
protected(ex) = Expr(:let, Expr(:function, :(), ex), map(reflect, symbolsof(ex))...) | |
const deferrals = gensym() | |
macro defer(ex) | |
quote | |
push!($deferrals, $(protected(ex))) | |
end |> esc | |
end | |
macro deferred(ex) | |
ex = longdef(ex) | |
isexpr(ex, :function) || error("call @deferred on a function") | |
Expr(:function, ex.args[1], quote | |
$deferrals = Function[] | |
try | |
$(macroexpand(ex.args[2])) | |
catch e | |
rethrow(e) | |
finally | |
for def in $deferrals | |
def() | |
end | |
end | |
end) |> esc | |
end | |
#= | |
EXAMPLE: | |
This code: | |
```julia | |
@deferred function open_lots_of_files_dangerously() | |
@defer println("Hello!") | |
for file in ["/dev/null", "/dev/zero", "this-file-doesn't-exist", "blah"] | |
f = open(file) | |
@defer close_loudly(f, file) | |
end | |
``` | |
expands to: | |
```julia | |
function open_lots_of_files_dangerously() # In[8], line 23: | |
##260 = Function[] # In[8], line 24: | |
try # In[8], line 25: | |
begin # In[11], line 2: | |
begin # In[8], line 15: | |
push!(##260,let println = println | |
function () | |
println("Hello!") | |
end | |
end) | |
end # In[11], line 3: | |
for file = ["/dev/null","/dev/zero","this-file-doesn't-exist","blah"] # In[11], line 4: | |
f = open(file) # In[11], line 5: | |
begin # In[8], line 15: | |
push!(##260,let close_loudly = close_loudly, f = f, file = file | |
function () | |
close_loudly(f,file) | |
end | |
end) | |
end | |
end | |
end | |
catch e # In[8], line 27: | |
rethrow(e) | |
finally # In[8], line 29: | |
for def = ##260 # In[8], line 30: | |
def() | |
end | |
end | |
end | |
``` | |
which does something very similar to what Go does. | |
=# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment