lua-users home
lua-l archive

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



Hi.

Thanks for the example! The example works perfectly. It took quite a while to figure out what is happening. I'm still having problems with metatables because I haven't used them very much.

However I have an additional question. If I create a table that checks if it's contents are changed can I prevent the table to be set to other type (for example normal table, number)? So basically can I prevent an assignment to variable referencing to the table?

Floru



Leandro Candido wrote:

Hello All,

    IF and IF you want, Florian, you can use a function (initializer) to
create each table, too, it's easy to use:

-- begin code

 function t( thetable )
  local meta = {}; -- or create a global one.
  function meta.__newindex( self, name, value )
   -- do what you want (track the value, etc...)
   -- ... --
   print(self, name, value); -- comment for normal use.
   rawget(self,"_______X")[name] = value; -- to allow meta call of
__newindex for X, if it has a metatab, see example in TWICE part below
  end
  function meta.__index( self, name )
      -- do what you want here...
      -- ... --
      print(self,name);
      return rawget(self,"_______X")[name]; -- to allow meta call of __index
for X.
  end
  local tab = { _______X = thetable }
  setmetatable( tab, meta);
  return tab;
 end

     mytable = t{ xyz = "123", lua_version = _VERSION }
     another = t(mytable);
     print(mytable.xyz);
     print(mytable.lua_version);
     print(mytable.nilfield);
     print("\nNow the metamethods will be called twice (THIS IS TO BE CALLED
TWICE):");
     print(another.xyz);
     print(another.lua_version);
     print(another.nilfield);
     print("\nNow, this will break our schema, of course:");
     mytab = t{}
     setmetatable(mytab,{});
     print(mytab.nilfield);

-- end code

You can "seach and replace" all "{" with "t{" in your .lua files, and you
will have what you want, but this can't be made automagically, as Virgil (or
others) stated.

                                                        The God's Peace,


Leandro.


----- Original Message -----
From: "Virgil Smith" <virgil@nomadics.com>
To: "'Lua list'" <lua@bazar2.conectiva.com.br>
Sent: Thursday, December 11, 2003 2:59 PM
Subject: RE: Checking if a table has changed



I suggest you check the wiki and the list archives for Lazy Copy or Deep
Copy (and/or RLake as I think he submitted the one I'm thinking of at the
moment).

You can copy any table placed into your hierarchy (using a proxy table at
each level).  This may seem inefficient, but I can't think of any other
language in which you wouldn't have the same basic copy problem (though I
don't doubt others have).  Basically, this relates to a question of
ownership of an "object" and/or to attributes of the "object's" type (in
this case a "modified" flag).  You could restrict tables added to your
hierarchy to be of a given "type" that supports a "modified" flag (and a
parent pointer for passing modification notices up the hierarchy if you so
choose).  The "type" of a table in Lua is related to its metatable.

An aspect of the copy approach is that you cannot be sure that "other"
references to the original table did not exist at the time that the table

in

question was inserted into your hierarchy.  However, one approach to this
would be to "hijack" the original table as the proxy table.  In other

words

rather than copying the contents of a table that is being "inserted" into
your hierarchy, you could <move> the contents into another table.  This
would result in any "stray" references to the inserted table going through
one of your proxy tables and thus you can maintain your "modified" flag.
One problem with this approach is that you must not only "hijack" the base
table, but also its metatable if it already has one.  However, a Lua table
with a metatable is essentially a user defined type, object, or "class
instance", and "seeing through" an unknown type to determine if it has

been

modified etc. is not a simple problem in any language.  Naturally,
userdata's are just as much of an "unknown type" as tables with

metatables,

and threads and functions bring up their own issues (though I'm not at all
sure about the "issues" with functions in this context).

Anyhoo, just my suggestions, perhaps you'll even find them useful. :-)
Also, if my use of the term "hierarchy" seems strange, try rereading the
message using "tree" in its place.



-----Original Message-----
From: lua-bounces@bazar2.conectiva.com.br
[mailto:lua-bounces@bazar2.conectiva.com.br]On Behalf Of Florian Berger
Sent: Thursday, December 11, 2003 8:25 AM
To: Lua list
Subject: Re: Checking if a table has changed



Thanks for the tip! I found code from lua-l archive (see below, I
modified it a little bit). The problem is that as you can see that it
does not work for nested tables. I could traverse recursively the
subtables through and call proxy for each table but I cannot do this
because of performance reasons. This cannot be automated somehow?

Floru


Source: http://lua-users.org/lists/lua-l/2003-07/msg00173.html

do
  local signature = {}

  -- set a proxy on table
  function proxy(table)
    local meta =
    {
      __index = table,

      __newindex = function(_, index, value)
        print('Modified!')
        table[index] = value
      end,

      __signature = signature,
    }

    return setmetatable({}, meta)
  end

  local n = next

  -- next replacement to support pairs and "old style" for loops
  function next(table, index)
    local m = getmetatable(table)
    return n(m and m.__signature == signature and m.__index or table,
index)
  end
end

local x = proxy( {{a = 1}, a = 1, b = 2} )

for k, v in pairs(x) do
  print(k, v)
end

x[1].a = 5
x.a = 2


Result:
1       table: 00379EB8
a       1
b       2
Modified!




Jamie Webb wrote:


On Thursday 11 December 2003 08:22, Florian Berger wrote:


Hi.

Is there a simple and efficient way to check if a table has changed? By
using metatables I'm able to catch some modifications but not all of

them.


You could use a proxy table with a __newindex which makes modifications

to

the

actual table and sets a 'modified' flag. Since the proxy table stays

empty,

__newindex is always called.

-- Jamie Webb

There are only 10 types of people in this world:
those who understand binary, and those who don't.