lua-users home
lua-l archive

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


I believe Pluto is one of the most important general-purpose additions
to Lua we have. I am currently trying to understand it a little better
for what I'm trying to do. It feels to me like Pluto's basic operation
is widely known and accepted, but subtleties and customisations are
not often discussed, which is a shame.

For example, one thing that I've noticed is that if you serialize a
Lua function and its environment table is the current global scope
(which is the majority of the time) Pluto will not serialize its
environment - instead, it will set its environment as nil, and then
when it is being unpersisted later, its environment table is set to
the current global scope at the time of unpersistance. Now, this makes
sense when you only want to serialize a function - otherwise, it would
always drag the entire global variable scope along with it - but it
can really screw things up when what you want to do is serialize the
entire global variable scope, and then after deserialization, use
lua_replace() to replace LUA_GLOBALSINDEX. All your Lua functions will
still be getting and setting variables from the *old* global variable
scope.

The only way I can see to work around this is to deliberately replace
the global scope with an empty table just before serialization, then
restore it immediately after. That way none of the function
environments will match the current global scope. Is there a better
way that I have missed? It will only work for using Pluto from the API
side, not the Lua interface.

Secondly, I am very interested in finding a way to have a custom
serialization behaviour for specific tables. I want to be able to have
tables that are serialized only as the *changes* between the current
version of the table, and a "pristine" version stored in the registry.
(The pristine version only contains functions, so sub-tables would
always be considered "changes" and get serialized, even if they
existed when the pristine version was made.)

I was hoping to be able to implement this using a custom __persist()
metamethod that generates a table which contains only the fields that
have changed from the "pristine" version (using a placeholder for
nil), and then returns a closure that merges the changes table back
into the pristine version to get the final restored table. And this
*almost* works - except where a key or value in the "changes" table
must refer directly or indirectly to the table that I am trying to
serialize. For example, if I try to use this to persist the global
variable scope, when it gets unpersisted again the _G field has been
set to nil, and every function has lost its function environment. (By
which I mean, it has been set to the global scope from before
deserialization, rather than set to the new global variable scope.)

I have not been able to find any workaround for this second problem. I
can see why it is happening - I'm indirectly telling Pluto to
serialize a table from inside its own __persist() metamethod, I
suppose I'm lucky that it's just setting it to nil instead of going
into an infinite loop. But I can't see any way to fix it. Has anyone
had any success with doing similar things with Pluto?

-Duncan