Thread Tools Display Modes
11-11-14, 03:21 PM   #1
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
Reading/Writting deep inside sparse tables

Hi just wanted to hear opinions on something I came up with to deal with elements in a sparse very deep table (in practical terms this happens to me with saved variables). For example, if I want to access a[3][7]["aa"][2][2], I need to first check if a, a[3], a[3][7], a[3][7]["aa"] and a[3][7]["aa"][2] exist, otherwise I would get an "attempt to index 'a' (a nil value)". With the following metamethods I can just:

Lua Code:
  1. local a = new_table()
  2. print(a(3,7,"aa",2,2)) --this prints nil as it should (since value was not set) but no errors
  3. a[3][7]["aa"][2][2] = "zzz" --sets everything in the path not set already: a[3], a[3][7], a[3][7]["aa"] etc
  4. print(a(3,7,"aa",2,2)) --this prints "zzz"

The only problem I can see is that you must use the proper forms depending if you are reading or writting, for example:
Lua Code:
  1. local b = new_table()
  2. print(b[1][1][1]) --instead of printing nil, this is the same as b[1]=new_table() b[1][1]=new_table() b[1][1][1]=new_table() and will print b[1][1][1] address (an empty table with a metatable attached)
  3. b(1,1,1) = "rrr" --this will not run: syntax error near '='
But I couldn't find a way to do both things (read and write) with the same format. Sorry if this sounds too trivial but it sounded like an Eureka! moment to me.


Lua Code:
  1. local mt = {}
  2.  
  3. mt["__index"] = function(t,k)
  4.     local v = setmetatable({},mt)
  5.     rawset(t,k,v)
  6.     return v
  7. end
  8.  
  9. mt["__call"] = function(t,...)
  10.     local i,n,v = 1,select("#",...),{...}
  11.     while t and i<=n do
  12.         t = rawget(t,v[i])
  13.         i = i+1
  14.     end
  15.     return t
  16. end
  17.  
  18. local new_table = function()
  19.     return setmetatable({},mt)
  20. end

How good do you think this is?


Last edited by Banknorris : 11-12-14 at 07:23 AM.
  Reply With Quote
11-11-14, 05:09 PM   #2
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
Actually, you should be able to write a value to it using the following syntax with no change to the code.
Code:
b[1][1][1] = "rrr"
Note with few exceptions, you can't make any function calls or evaluations happen on the left side of the assignment operator.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
11-11-14, 06:47 PM   #3
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
Originally Posted by SDPhantom View Post
Actually, you should be able to write a value to it using the following syntax with no change to the code.
Code:
b[1][1][1] = "rrr"
Well that was my first example (line 3). In case people are missing what is the point, the point is that by using those meta-methods, you can avoid doing this:
b[1]={}
b[1][1]={}
b[1][1][1]="rrr"
and instead just write the last line since the meta-methods will do this job for you.
b[1][1][1]="rrr"
also, instead of this:
if b[1] and b[1][1] and b[1][1][1]=="rrr" then
you can just
if b(1,1,1)=="rrr" then

Last edited by Banknorris : 11-11-14 at 06:50 PM.
  Reply With Quote
11-11-14, 11:14 PM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Banknorris View Post
also, instead of this:
Code:
if b[1] and b[1][1] and b[1][1][1]=="rrr" then
you can just
Code:
if b(1,1,1)=="rrr" then
But function calls are so slow.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
11-12-14, 07:55 AM   #5
AlleyKat
A Warpwood Thunder Caller
 
AlleyKat's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 93
I made better infinite table example for u

Lua Code:
  1. local setmetatable = setmetatable;
  2. local rawget = rawget;
  3. local type = type;
  4. local secondLayer, getVal;
  5.      
  6. local newTable = function()
  7.     return setmetatable({}, secondLayer);
  8. end;
  9.  
  10. getVal = function(s, v, ...)
  11.     local t = rawget(s, v);
  12.     if t == nil or type(t) ~= "table" then
  13.         return t;
  14.     else
  15.         return getVal(t, ...);
  16.     end
  17. end
  18.  
  19. secondLayer = { __index = function(self, key)
  20.     local new = newTable();
  21.     self[key] = new;
  22.     return new;
  23. end, __call = getVal};
  24.  
  25. -----
  26. local a = newTable();
  27. a[1][2][3] = 1;

... or not

Last edited by AlleyKat : 11-12-14 at 09:04 AM.
  Reply With Quote
11-12-14, 08:44 PM   #6
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
Originally Posted by Banknorris View Post
also, instead of this:
Code:
if b[1] and b[1][1] and b[1][1][1]=="rrr" then
you can just
Code:
if b(1,1,1)=="rrr" then
With the same __index metamethod, you don't need to call the table's __call metamethod anyway.

Let's look at the following code:
Code:
if b[1][1][1]=="rrr" then
If any of the indexing operations result in a nil return, the __index metamethod will jump in anyway and return a new table along with setting the returned table to the associated index. The end result would be comparing an empty table with "rrr" in such case.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Reading/Writting deep inside sparse tables


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off