Point table to another table in Lua

1.6k views Asked by At

is there any way to point table to another table? for example:

local a = {}
local b = {}
a.name = "Josh"
print(a.name) -- Prints 'Josh'
print(b.name) -- Prints 'Josh' aswell
a.name = "I don't have a name"
print(a.name) -- Print 'I don't have a name'
print(b.name) -- Prints 'I don't have a name' aswell

I hope you get my point.. thanks

EDIT:

Okay, so here is the idea:

I am making a dinamic function that is like this

local table = { 1, 2, "hey" }

function drawimage(name, posx, posy referencetable)
    _tabledata[name] = { posx = posx, posy = posy, reference = {}}
    setmetatable(_tabledata[name].reference, { __index = referencetable })
end

drawimage("Header", 0, 50, table)

All good and fine, values work and we are all happy.. the problem occurs when the reference table changes it's value in this way

local data = { 123123, 545454, "heyou" } -- Data is sent from another script via a trigger
table = data

Since I am not updating it by an index (ie: table[1] = 9999) reference variable is 'unsynced' with the real one, I hope you understand :)

EDIT2:

Okay here is a self working example of my main problem

local maintable = { "Stack", "Overflow" }
local maintablecopy = {}

maintablecopy = maintable

print("maintable[1] = " ..maintable[1]) -- Prints Stack
print("maintable[2] = " ..maintable[2]) -- Prints Overflow
print("")
print("maintablecopy[1] = " ..maintablecopy[1]) -- Prints Stack
print("maintablecopy[2] = " ..maintablecopy[2]) -- Prints Overflow
print("")

print("Changing values..")
local newdata = { "Hello", "World" }
maintable = newdata

print("")
print("maintable[1] = " ..maintable[1]) -- Prints Hello
print("maintable[2] = " ..maintable[2]) -- Prints World
print("")
print("maintablecopy[1] = " ..maintablecopy[1]) -- Prints Stack    -- PROBLEM
print("maintablecopy[2] = " ..maintablecopy[2]) -- Prints Overflow -- PROBLEM

print("Using setmetatable..")

maintable = { "Stack", "Overflow" }
maintablecopy = {}
setmetatable(maintablecopy, { __index = maintable })

print("maintable[1] = " ..maintable[1]) -- Prints Stack
print("maintable[2] = " ..maintable[2]) -- Prints Overflow
print("")
print("maintablecopy[1] = " ..maintablecopy[1]) -- Prints Stack
print("maintablecopy[2] = " ..maintablecopy[2]) -- Prints Overflow
print("")

print("Changing values..")
local newdata = { "Hello", "World" }
maintable = newdata

print("")
print("maintable[1] = " ..maintable[1]) -- Prints Hello
print("maintable[2] = " ..maintable[2]) -- Prints World
print("")
print("maintablecopy[1] = " ..maintablecopy[1]) -- Prints Stack    -- PROBLEM
print("maintablecopy[2] = " ..maintablecopy[2]) -- Prints Overflow -- PROBLEM

Why I cannot directly point it to the table when the variable updates? becouse I have 20 tables to update, it would be easier to do this

local _dynamics = {}

local tbl1 = { "Hey", 8787 } 
local tbl2 = { 123, "There" }
local tbl3 = { "You", 1111 }  

function dynamicFunction(name, posx, posy, textsize, reference)
    _dynamics[name] = { posx = posx, posy = posy, textsize = textsize, reference = reference }
end

dynamicFunction("first", 0, 0, 5, tbl1)
dynamicFunction("second", 0, 0, 5, tbl2)
dynamicFunction("third", 0, 0, 5, tbl3)

for key in pairs(_dynamics) do
    local inf = _dynamics[key]
    for i = 1, #inf.reference do
        print(inf.reference[i])
        if i == #inf.reference then
            print("")
        end
    end
end

print("")
print("")

tbl1 = { "aaaaa", "bbbbbbbbbb" }
tbl2 = { "ccccccccccc", "ttttttttttt" }
tbl3 = { "rrrrrrr", "yyyyyyyyyyy" }

for key in pairs(_dynamics) do
    local inf = _dynamics[key]
    for i = 1, #inf.reference do
        print(inf.reference[i])
        if i == #inf.reference then
            print("")
        end
    end
end

print("Values should get updated on the reference variable, but it doesn't.. this would save me     to do a check for every single variable")

You can run it on http://www.compileonline.com/execute_lua_online.php to see yourself what I mean.

Sorry if it's a mess but my english is not the best :D

1

There are 1 answers

5
Phrogz On

You want the __index metamethod:

local a = { name="Josh" }
local b = {}

print(a.name) --> Josh
print(b.name) --> nil

setmetatable(b,{__index=a})
print(b.name) --> Josh

a.name = "Gilligan"
print(a.name) --> Gilligan
print(b.name) --> Gilligan

-- but note! the shadow
b.name = "overridden"
print(a.name) --> Gilligan
print(b.name) --> overridden

b.name = nil
print(a.name) --> Gilligan
print(b.name) --> Gilligan

For more details, I offer up this article of mine:
http://phrogz.net/lua/LearningLua_ValuesAndMetatables.html


Response to Edit2:

Let me summarize the problems with some of your code:

local maintablecopy = {}
maintablecopy = maintable

With the above code you create one table, set maintablecopy to reference that table, and then you completely abandon it when you set maintablecopy to instead reference a different table. This demonstrates a lack of understanding of how variables work.

local newdata = { "Hello", "World" }
maintable = newdata

Again, you are not "copying" newdata into maintable, you are changing the variable to reference the same table here.

maintable = { "Stack", "Overflow" }
maintablecopy = {}
setmetatable(maintablecopy, { __index = maintable })

-- …

local newdata = { "Hello", "World" }
maintable = newdata

Again, same problem. Here are some ways to change your code:

Replace a Table's Contents

Instead of maintable = newdata you could do this:

function copytable(from,to_table)
  -- erase all old keys
  for k,_ in pairs(to_table) do to_table[k] = nil end

  -- copy the new ones over
  for k,v in pairs(from) do to_table[k] = v end
end

local a = { name="Foo" }
local b = {}
copytable(a,b)
print(a.name == b.name) --> true

local c = { name="NEW" }
copytable(c,b)
print(c.name == b.name) --> true

However, doing this will not cause b to update if c changes.

c.name = "EVEN NEWER"
print(c.name == b.name) --> false

Update the __index

local a = { name="Foo" }
local b = setmetatable({},{__index=a})
print(a.name == b.name) --> true

-- cause b to follow c now instead of a
local c = { name="NEW" }
getmetatable(b).__index = c
print(c.name == b.name) --> true

c.name = "EVEN NEWER"
print(c.name == b.name) --> true

In general, you need to step back and describe the original problem you are trying to solve, instead of this XY problem.