The function g
(or solver
) isn’t a closure. The global variables a
, b
, and c
are looked up dynamically (in your language: they get “tracked”). Note the Main.a
, Main.b
, and Main.c
in the lowered code that indicates this:
julia> @code_lowered g(x)
CodeInfo(
1 ─ %1 = Core.apply_type(Base.Val, 2)
│ %2 = (%1)()
│ %3 = Base.literal_pow(Main.:^, x, %2)
│ %4 = Main.a * %3
│ %5 = Main.b * x
│ %6 = %4 + %5 + Main.c
└── return %6
)
The function addFive
is a closure. It is the value of a
that gets stored inside of the function (rather than a dynamic lookup). Note that, according to my understanting of the concept of a closure, a crucial property is that the closed-upon variable is actually wrapped. For addFive
we can actually access y
:
julia> propertynames(addFive)
(:y,)
julia> addFive.y
5
I’d say the statement, as you stated / cited it, is partially incorrect and partially correct. When you copy the definition of a
, b
, and c
into the definition of g
, i.e.
function g(x)
a, b, c = 1, 2, 3
a*x^2 + b*x + c
end
the variables a
, b
, and c
indeed become local variables. However, I wouldn’t call g
a closure in this case as it doesn’t wrap a
, b
, c
, in the sense of “private variables”.
julia> function g(x)
a, b, c = 1, 2, 3
a*x^2 + b*x + c
end
g (generic function with 1 method)
julia> propertynames(g)
()
In fact, generally speaking, the compiler might optimize all local variables away if it can prove that this doesn’t have an observable effect.
But perhaps one may call this a closure nonetheless? Someone wiser should speak to this