Table Funcs Two

lua-users home
wiki

Here is a version of TableFuncs in which there is both a private and a public persistent state.

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


RecentChanges · preferences
edit · history
Last edited May 28, 2007 5:16 pm GMT (diff)