lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Nick Davies:
> In the following code:
>
> function create()
>     local e = {}
>     e.x = 0
>     e.update = function(self)    -- mark
>         self.x = self.x + 1
>     end
>     return e
> end
>
> e1 = create()
> e2 = create()
> e3 = create()
>
> How many copies are created of the 'update' function at the marked line?
> One, shared among e1, e2, and e3, or three, one for each of e1, e2, and
> e3?
>
> I am planning on doing this sort of thing quite a bit in my current Lua
> project and I'm concerned a bit about memory efficiency and such.


Nick Trout:
> a closure is created in every function call to create() but this only
> creates one function.

That seems a fairly definite statement that closures are not shared, even if
they are the same (although at least the function code is shared). If
efficiency is a problem then you'd be best off creating a single closure and
passing it around. Eg:

-- Use a 'do/end' block so that the local 'temp' does not pollute
-- the name space.
do
  -- The local variable 'temp' is assigned a closure.
  local function temp(self)
    self.x = self.x + 1
  end

  -- Define the function 'create'. Every time it executes it
  -- assigns a reference to the closure stored in 'temp'.
  function create()
    local e = {}
    e.x = 0
    e.update = temp
    return e
  end
end

The key here is that (as far as I understand it) a closure is created each
time the 'function' expression/statement is encountered. So if you only
execute it once then you save memory duplication.

Binding a 'function' expression more than once is only needed if it wraps
lexically scoped variables within its closure, otherwise it is inefficient
(even if it might look neater).

Eg, if you had something like:
  function create(init)
    local e = {}
    e.x = 0
    e.reset = function temp(self) self.x = init end
    return e
  end

then you need the separate closure, since each separate closure instance
refers to a different 'init' variable from the surrounding lexical scope!

So:
  e1 = create(111)
  e2 = create(222)
  e1.reset -- resets to '111'
  e2.reset -- resets to '222'.

*cheers*
Peter Hill.