lua-users home
lua-l archive

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


> However it requires ephemerons and thus Lua 5.2 to work, doesn't it?

Not exactly (see below).


> I read http://www.inf.puc-rio.br/~roberto/docs/ry08-06.pdf when
> trying to understand what it does, which was very instructive, but I
> still don't understand how calling mksentinel(obj) again in the
> sentinel's __gc method can save the obj. Isn't it too late also for
> obj when the sentinel's __gc is run?

No. 'obj' is still "alive" both as a upvalue for the sentinel's
finalizer and in the ephemeron. While a finalizer can access an object,
the object cannot be collected.  (However, if 'obj' had its own
finalizer, it would run in the first collection cycle after 'obj' became
not directly accessible.).


> >(Note that you cannot use the __gc metamethod of
> >'myobject', as it will be called once the object becomes gargage; you
> >must use 'collect' to finalize the object.)
> 
> So myobject's __gc metamethod is called every time the (sentinel,
> obj) pair is dropped from the anchor table?

No. It is called only once. Any finalizer is called only once for each
object, no matter what happens. That is why each sentinel must create a
new sentinel, with a new finalizer to be called.


> I understand that we thus have to do any finalization work in
> collect() instead, but I still wonder how mksentinel(obj) can save
> the obj when it seems that internally to Lua it was marked for
> collection at the time when the sentinel key in anchor became
> collectible.

As I said, 'obj' is still "weakly reachable" both in the ephemeron (it
will be there until its key is actually collected) and as an upvalue in
the sentinel's finalizer. We do not need both tricks. For instance, the
sentinel's finalizer could start like this:

    {__gc = function (s)
              local obj = anchor[s]      --<< change
              if not cancollect(obj) then
                ...

Now 'obj' is no more an upvalue for the finalizer, but it is still
available in the ephemeron table.


> I assume there is no easy alternative of this code for Lua 5.1?

There is, see below. The code is quite similar, but it uses proxies
instead of tables for the sentinel (tables have no finalizers in 5.1)
and does not use the ephemeron. The downside is that 'obj' now cannot
be reachable in general, except by the sentinel's finalizer. With the
ephemeron, 'obj' is accessible all the time through the anchor.

-- Roberto


------ version for Lua 5.1

myobject = {name = "my object"}


local function cancollect (obj)
  print("may I collect object " .. obj.name .. "?")
  return (io.read() == "yes")
end


local function collect (obj)
  print("collecting " .. obj.name)
end


local function mksentinel (obj)
  local sentinel = newproxy(true)
  getmetatable(sentinel).__gc = function (s)
              if not cancollect(obj) then
                mksentinel(obj)
              else
                collect(obj)
              end
            end
  obj.sentinel = sentinel
end

mksentinel(myobject)


print(1); collectgarbage()
print(2); collectgarbage()
myobject = nil
print(3); collectgarbage()
print(4); collectgarbage()
print(5); collectgarbage()
print(6); collectgarbage()