lua-users home
lua-l archive

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


On Thu, Oct 8, 2009 at 5:59 PM, Ben Sunshine-Hill <sneftel@gmail.com> wrote:
> A bit of historical perspective:
>
> When I originally designed Pluto, although I considered the
> possibility of serializing the globals table, it was my feeling that
> people wouldn't normally do it. This was partially because my
> preferred coding style with Lua tended to keep things out of the
> global scope, and partially because I felt that if one was serializing
> such a huge amount of the Lua space, a solution like lper (which, BTW,
> is awesome and deserves to be updated and used more) would be a better
> fit.

lper is great, but unfortunately as Luiz pointed out, it is Linux-only
and that's a bit of a deal-breaker for what I'm doing at the moment.

> My "solution" for persisting the global table, then, was a lazy one:
> Someone who wished to persist the globals table would do so by putting
> a whole bunch of stuff in the permanents table... basically, every
> library and global function that shouldn't be messed with. The globals
> table would then be serialized, either directly or in a location
> directly accessible from the serialized object. Then on reload, the
> reloaded table (not yet the globals table) would be reintegrated into
> the real globals table through a simple "for k,v in pairs(t) do
> _G[k]=v end". This isn't a perfect approach, as _G itself could be
> held as a reference by an object, and on unserialize this would then
> point to the not-the-global-table result. Normally one would deal with
> this by keeping such an object in the permanents table, but in this
> instance of course that wouldn't work, as _G needs specifically to NOT
> be a permanent object. Other than that caveat, however, this approach
> should work fine.

I'd probably be happy with that approach if the only Lua code that I
was going to be dealing with would be my own, but I'm planning to use
Pluto transparently for Lua code written by other people, and I'm sure
they would find odd ways to sneak references to _G all over the place.
(I suppose I could remove the _G global variable, but then there's
getfenv(), and I really don't want to mess with what's available as
standard in the Lua "universe" unless I really have to.)

> For your second need, it seems like the laziest solution would be to
> put the onus on maintaining changes from the pristine to the maculate
> table on the table itself. This is a common thing to do with Pluto,
> with __index and __newindex metamethods capable of delegating to the
> pristine table for unchanged values, and the table itself for changes
> (including, and this is an important problem, values which have been
> set to nil). Then there's nothing special about serializing it, not
> even a need for a __persist metamethod -- just stick the pristine
> table in the permanents.

Yeah, that works - I hadn't considered other forms of "magic" than
__persist(). Thanks!

> On Thu, Oct 8, 2009 at 9:52 AM, Duncan Cross <duncan.cross@gmail.com> wrote:
>> Another subtle thing to watch out for is that, if you want to
>> serialize the global variable scope, it is easy to forget about the
>> string metatable which will still have its __index field set to the
>> *old* string table - so if you add custom functions to string, and
>> want to call them as methods, they seem to disappear after
>> serialization and deserializatin. The solution is to serialize not the
>> global variable scope itself but a temporary table that contains it,
>> as well as the string metatable, and possibly other base-type
>> metatables if you have set them.
>
> Huh, yikes.

Yikes at the problem, or my solution? :)

Another thing I've realised is that coroutine.wrap() returns a
C-function that you cannot put into the permanents table ahead of time
as it is allocated each time with an upvalue. I think the solution
there is to reimplement it as a Lua function:

do
  local select, assert, cocreate, coresume = select, assert,
coroutine.create, coroutine.resume
  function coroutine.wrap(f)
    local th = cocreate(f)
    return function(...)
      return select(2, assert(coresume(th, ...)))
    end
  end
end

(Anyone have any criticism of that implementation?) Of course once you
go down that road, there is also the iterators returned by ipairs(),
pairs(), io.lines() and string.gmatch() that could potentially be on
the stack of a suspended coroutine, so they would need to be
reimplemented as well...

-Duncan