Search code examples
luametatable

Lua modify metatable properties from parent table


I have this code, but I don't want the tbl variable getting width and height assigned to it, rather I want base_table's width and height properties getting modified to 200 rather than tbl getting assigned a height and width of 200.

function deepCopy(original)
    local copy = {}
    for k, v in pairs(original) do
        if type(v) == "table" then
            v = deepCopy(v)
        end
        copy[k] = v
    end
    return copy
end

function PrintTable(t)
    for k, v in pairs(t) do
        if v == "table" then
            PrintTable(v)
        else
            print(k, v)
        end
    end
end

local base_table = {
  width = 0,
  height = 0,
  x = 0,
  y = 0,

  SetSize = function(self, w, h)
    self.width, self.height = w, h
  end,

  SetPos = function(self, x, y)
    self.x, self.y = x,y
  end

}

local tbl = {}

local meta = {__index = deepCopy(base_table)}

setmetatable(tbl, meta)


PrintTable(tbl) -- prints nothing

tbl:SetSize(200, 200)

PrintTable(tbl) -- prints height 200, width 200 which I don't want, I want it to print nothing like above. though if I do tbl.x I want it to 200, since it would be on the metatable, rather than the tbl itself 

Solution

  • local function deepCopy(original)
       local copy = {}
       for k, v in pairs(original) do
          if type(v) == "table" then
             v = deepCopy(v)
          end
          copy[k] = v
       end
       return copy
    end
    
    local function PrintTable(t)
       for k, v in pairs(t) do
          if v == "table" then
             PrintTable(v)
          else
             print(k, v)
          end
       end
    end
    
    local base_table = {
       width = 0,
       height = 0,
       x = 0,
       y = 0,
    
       SetSize = function(self, w, h)
          self.width, self.height = w, h
       end,
    
       SetPos = function(self, x, y)
          self.x, self.y = x,y
       end
    
    }
    
    local tbl = {}
    local cpy = deepCopy(base_table)
    setmetatable(cpy, {__newindex = function(_, k, v) rawset(tbl, k, v) end})
    setmetatable(tbl, {__index = cpy; __newindex = cpy})
    
    PrintTable(tbl) -- prints nothing
    
    tbl:SetSize(200, 200)
    tbl.someproperty = "some value"
    
    PrintTable(tbl) -- prints only someproperty