Julia Language Introduction to Closures


Example

Functions are an important part of Julia programming. They can be defined directly within modules, in which case the functions are referred to as top-level. But functions can also be defined within other functions. Such functions are called "closures".

Closures capture the variables in their outer function. A top-level function can only use global variables from their module, function parameters, or local variables:

x = 0  # global
function toplevel(y)
    println("x = ", x, " is a global variable")
    println("y = ", y, " is a parameter")
    z = 2
    println("z = ", z, " is a local variable")
end

A closure, on the other hand, can use all those in addition to variables from outer functions that it captures:

x = 0  # global
function toplevel(y)
    println("x = ", x, " is a global variable")
    println("y = ", y, " is a parameter")
    z = 2
    println("z = ", z, " is a local variable")

    function closure(v)
        println("v = ", v, " is a parameter")
        w = 3
        println("w = ", w, " is a local variable")
        println("x = ", x, " is a global variable")
        println("y = ", y, " is a closed variable (a parameter of the outer function)")
        println("z = ", z, " is a closed variable (a local of the outer function)")
    end
end

If we run c = toplevel(10), we see the result is

julia> c = toplevel(10)
x = 0 is a global variable
y = 10 is a parameter
z = 2 is a local variable
(::closure) (generic function with 1 method)

Note that the tail expression of this function is a function in itself; that is, a closure. We can call the closure c like it was any other function:

julia> c(11)
v = 11 is a parameter
w = 3 is a local variable
x = 0 is a global variable
y = 10 is a closed variable (a parameter of the outer function)
z = 2 is a closed variable (a local of the outer function)

Note that c still has access to the variables y and z from the toplevel call — even though toplevel has already returned! Each closure, even those returned by the same function, closes over different variables. We can call toplevel again

julia> d = toplevel(20)
x = 0 is a global variable
y = 20 is a parameter
z = 2 is a local variable
(::closure) (generic function with 1 method)

julia> d(22)
v = 22 is a parameter
w = 3 is a local variable
x = 0 is a global variable
y = 20 is a closed variable (a parameter of the outer function)
z = 2 is a closed variable (a local of the outer function)

julia> c(22)
v = 22 is a parameter
w = 3 is a local variable
x = 0 is a global variable
y = 10 is a closed variable (a parameter of the outer function)
z = 2 is a closed variable (a local of the outer function)

Note that despite d and c having the same code, and being passed the same arguments, their output is different. They are distinct closures.