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 4:16 pm GMT (diff)