Metatable __index issues

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Metatable __index issues

Tim Conkling-2
In the following code:

> table = {}
> table.var = 3
> metatable = {}
> metatable.__index = function(table, key) print("__index called") end
> setmetatable(table, metatable)
> print(table.var)
3
> print(table.var2)
__index called
nil

Why doesn't the __index metamethod get called when I access table.var? The
reference manual simply says '"index": the indexing access table[key]' to
describe when this function gets called.

I am trying to protect a table from being modified, and I thought the best
way to do this would be through metatables, but this doesn't seem to
working, because my metamethods are not being called when I thought they
would be (specifically, the __index method is not being called). How do I
protect this table?

Thanks,
Tim
-- 
Tim Conkling
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Metatable __index issues

Eric Tetz-2
--- Tim Conkling <[hidden email]> wrote:
> Why doesn't the __index metamethod get called when I access
> table.var? The reference manual simply says '"index": the
indexing
> access table[key]' to describe when this function gets called.

Yeah, the manual's one-liner synopsis is misleading, but the
synposis is followed by clarifiying pseudocode (lua code actually):

if type(table) == "table" then
     local v = rawget(table, key)
     if v ~= nil then return v end
     ...

In other words, __index metamethod is only called if 'key' does not
exist in the table.

> I am trying to protect a table from being modified, and I thought
> the best way to do this would be through metatables

Well, since __index is called if 'key' doesn't exist, you could use
a stand-in for the table that has no keys:

local proxy_metatable = {}

proxy_metatable.__index = 
  function(proxy, key) 
    return rawget(getmetatable(proxy)[proxy], key)
  end

proxy_metatable.__newindex = 
  function(table, key, value) 
  end

function make_readonly(table)
  local proxy = {}
  proxy_metatable[proxy] = table
  setmetatable(proxy, proxy_metatable)
  return proxy
end


-----------------
-- Example usage:
-----------------

t = {}
t.a = "apple"
t.b = "ball"
t = make_readonly(t)

print(t.a, t.b)
t.a = "ardvaark"
t.b = "bat"
print(t.a, t.b)


__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free, easy-to-use web site design software
http://sitebuilder.yahoo.com

Reply | Threaded
Open this post in threaded view
|

Re: Metatable __index issues

Mark Hamburg-4
I just skimmed through the specs on Sol and one of the things I liked about
it was that it had metamethods that were always called when reading or
writing tables. I've been looking at building a persistent data-store for
Lua (without using memory mapping tricks) and one of the things I need is a
way to know when a table becomes dirty so that it can go on the
needs-to-be-written-to-disk list. The only way to do that in Lua seems to be
to use a proxy table but that means that every persistent table is now two
tables.

Sol makes some rather interesting choices, many of which seem good. On the
other hand, there is a community of Lua users and I had a hard time just
finding the details on Sol.

Mark


Reply | Threaded
Open this post in threaded view
|

Re: Metatable __index issues

Vinicius da Silva Almendra
In reply to this post by Tim Conkling-2
Hello,

  I found out what seems to be a bug (correct me if I'm wrong...) in Lua5:  
when setting numeric indices in a table, the __index metamethod is called
whether or not the field has an associated value.


  
Best regards,

  Vinicius Almendra
  TeCGraf researcher




----------------
Original Message
----------------

Date: Fri, 15 Aug 2003 23:07:15 -0700 (PDT)
From: Eric Tetz <[hidden email]>
Subject: Re: Metatable __index issues
To: Lua list <[hidden email]>
Message-ID: <20030816060715.25064.qmail@...>
Content-Type: text/plain; charset=us-ascii

--- Tim Conkling <[hidden email]> wrote:
> Why doesn't the __index metamethod get called when I access
> table.var? The reference manual simply says '"index": the
indexing
> access table[key]' to describe when this function gets called.

Yeah, the manual's one-liner synopsis is misleading, but the
synposis is followed by clarifiying pseudocode (lua code actually):

if type(table) == "table" then
     local v = rawget(table, key)
     if v ~= nil then return v end
     ...

In other words, __index metamethod is only called if 'key' does not
exist in the table.

> I am trying to protect a table from being modified, and I thought
> the best way to do this would be through metatables

Well, since __index is called if 'key' doesn't exist, you could use
a stand-in for the table that has no keys:

local proxy_metatable = {}

proxy_metatable.__index = 
  function(proxy, key) 
    return rawget(getmetatable(proxy)[proxy], key)
  end

proxy_metatable.__newindex = 
  function(table, key, value) 
  end

function make_readonly(table)
  local proxy = {}
  proxy_metatable[proxy] = table
  setmetatable(proxy, proxy_metatable)
  return proxy
end


-----------------
-- Example usage:
-----------------

t = {}
t.a = "apple"
t.b = "ball"
t = make_readonly(t)

print(t.a, t.b)
t.a = "ardvaark"
t.b = "bat"
print(t.a, t.b)


__________________________________


Reply | Threaded
Open this post in threaded view
|

Re: Metatable __index issues

Roberto Ierusalimschy
>   I found out what seems to be a bug (correct me if I'm wrong...) in Lua5:  
> when setting numeric indices in a table, the __index metamethod is called
> whether or not the field has an associated value.

__index is called when setting indices?? Or is it __newindex? Can you send
a small example?

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Metatable __index issues

Eric Tetz-2
In reply to this post by Mark Hamburg-4
--- Mark Hamburg <[hidden email]> wrote:
> The only way to do that in Lua seems to be to use a proxy table
> but that means that every persistent table is now two tables.

Oh, it means more than that. ;) The proxy has limitations. For
instance, you can no longer say "for k,v in mytable", and the proxy
itself is not protected from modification by metatable-unaware
functions like "table.insert". It's a bit of a kludge, no doubt.

Cheers,
Eric


__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free, easy-to-use web site design software
http://sitebuilder.yahoo.com