Table Funcs Two |
|
For efficiency, this has the restriction that private keys cannot have the value nil
(setting a private key to nil will publish the key). Now that we have false
I don't think this is so crucial. (OK, maybe false
was not a bad idea :) )
The interesting thing is that there are no reserved keys in the public state table, and client programs can freely use keys which happen to be private. In this case, the client program and the tablefunc see different tables.
I didn't put in any inheritance here, but that is not very difficult. The private table needs to check the private table of the object it inherits from before trying the public table, and the public table just has an __index
metamethod whose value is the public table of the same object. This is more like object prototyping than class inheritance, but it is often a useful programming style.
do -- the private table just forwards to the public table. local private_meta = { __index = function(t, k) return t.__public[k] end, __newindex = function(t, k, v) t.__public[k] = v end, __call = function(t, ...) return t.__function(t, unpack(arg)) end } function Tablefunc(fn, private) -- this is what the caller will see local public = {} -- remember what we do and where we do it private.__function = fn private.__public = public -- normally I'm not in favour of privatisation, but -- sometimes you have to do it. -- Call this as follows: -- self:privatise {private_key = initial_value, -- other_private_key = initial_value} function private.privatise(self, vars) for k, v in vars do rawset(self, k, v) end end -- set up the deferral metamethods setmetatable(private, private_meta) -- create a new metatable with a __call metamethod which -- accesses the private table through a closure. return setmetatable(public, { __call = function(t, ...) return private.__function(private, unpack(arg)) end }) end end
Let's take it for a little spin.
function test(self, x) if x then self:privatise({public = "public hidden"}) end print("hidden:", self.hidden) print("public:", self.public) end
$lua Lua 5.0 (beta) Copyright (C) 1994-2002 Tecgraf, PUC-Rio > a = Tablefunc(test, {hidden = "hidden"}) > a() hidden: hidden public: nil > a.public = "public" > a() hidden: hidden public: public > a.hidden = "change hidden" > a() hidden: hidden public: public > = a.hidden change hidden > -- here we tell the function to make "public" private > a(1) hidden: hidden public: public hidden > = a.public public > a.public = "change public" > a() hidden: hidden public: public hidden > = a.public change public
--RiciLake