Phrogz
Phrogz

Reputation: 303510

Alternative value for a Lua table (as a whole)

I believe the answer to this is "no", but I need to ask anyhow:

I have several nested tables of values, mostly with the same ~"schema" (hierarchy of names). For example, theme.person.child has a value in each of these nested tables, e.g. a string like "#ffcc33".

Sometimes I would like to be able to reference theme.person (which is usually a table) and "get" a string value instead of a name. I want a default value for all person, regardless of the sub-key.

Is there any metamethod/key that would let me call the same function on table.person.child and table.person and always get a string? In code:

local theme1 = { person = { child='#ffcc33', adult='#00ffff', _default='#ff0000' } }
local theme2 = { person = '#ff0000' }
for _,theme in ipairs{ theme1, theme2 } do
    print(somefunction(theme))
end

Is there any way to make both print statements output give #ff0000'? Some magic other than :

function somefunction(x) return type(x)=='table' and x._default or x end

Upvotes: 1

Views: 367

Answers (1)

Jason Goemaat
Jason Goemaat

Reputation: 29234

This is a little odd how you have this organized, but is this what you want? 'person' has to be a hard-coded property, or do you want to search all properties for _default if they are a table?

local theme1 = { person = { child='#ffcc33', adult='#00ffff', _default='#ff0000' } }
local theme2 = { person = '#ff0000' }

function somefunction(tbl, param)
  if type(tbl) == 'string' then return tbl end
  return tbl._default
end

for _,theme in ipairs{theme1, theme2} do
  print (somefunction(theme.person))
end

codepad

You could possibly use metatables if there's a standard you want to use, but then you have to set them on each table. __tostring on a metatable would let you return whatever string you want when the table is converted to a string. In the code below I set the metatable on the person in theme1 so that it returns the _default when doing a tostring() on the table. __index lets you return whatever values you want when a table is indexed. Here it works like a color property that returns person._default if person is a table or person otherwise.

local personmt = {
  __tostring = function(t)
    if type(t) == 'table' and t._default ~= nil then return t._default end
    return tostring(t)
  end
}

local thememt = {
  __index = function(t, k)
    if k == 'color' then
      if type(t.person) == 'table' then return t.person._default end
      return t.person
    end
  end
}

local theme1 = { person = { child='#ffcc33', adult='#00ffff', _default='#ff0000' } }
local theme2 = { person = '#ff0000' }

setmetatable(theme1.person, personmt)

for _,theme in ipairs{ theme1, theme2 } do
    setmetatable(theme, thememt)
    print('theme.person (__tostring):', theme.person)
    print('theme.color (__index)    :', theme.color)
end

codepad

Upvotes: 1

Related Questions