Closure with let block: Simpler syntax for capturing variables?

The example is taken from the post "A Tragedy of Julia’s Type System" - #30 by foobar_lv2

function f()
   x = 0
   if false x=1 end
   g = let x=x
      () -> x
   end
end

This form is suggested in the manual, and indeed the @code_warntype shows no warning.

My question is about the syntax x=x. Sometimes I want to captures several variables, and get let foo=foo, bar=bar, .... It seems stupid to repeat the same words, and indeed it reduces the readability when the variables’ names are long.

I’m wondering if it’s possible to have syntax like let ;foo, bar, as in the function call with keywords we can do fn(; foo, bar).

1 Like

Here’s one way you could do it:

macro localize(args...)
    to_localize = args[1:end-1]
    ex = args[end]
    esc(Expr(:let, Expr(:block, (:($x=$x) for x ∈ to_localize)...), ex))
end

and then

julia> @macroexpand @localize x y z () -> x + y + z
:(let x = x, y = y, z = z
      ()->begin
              #= REPL[11]:1 =#
              x + y + z
          end
  end)

Then your example would be written

function f()
   x = 0
   if false x=1 end
   g = @localize x () -> x
   end
end

Nice, just had the same idea … albeit with a slightly different syntax resembling closures in C++:

using MacroTools

macro closure(expr)
    @assert @capture expr ([binds__](args__) -> body_)
    @assert all(x -> isexpr(x, Symbol), binds)
    bindings = [:($(esc(v)) = $(esc(v))) for v in binds]
    Expr(:let, Expr(:block, bindings...), Expr(:->, Expr(:tuple, esc.(args)...), esc(body)))
end

To be used like …

julia> @macroexpand @closure [x, y](z) -> x*z + y
:(let x = x, y = y
      (z,)->begin
              #= REPL[73]:1 =#
              x * z + y
          end
  end)
1 Like

If we’re looking for macro workarounds, there’s also FastClosures.jl, which identifies the captured variables for you:

using FastClosures

function f()
   x = 0
   if false x=1 end
   g = @closure () -> x
end
3 Likes

Thank you guys! Hopefully some of these efforts can be merged into the language itself.

1 Like