4

I have a table called frameActions which could not contain some property in some case:

action = 'UP'
frameActions = {}
frameActions['UP'] = { a = 1, b = 2 }

How do I check if the table have a specific property name?

if frameActions[action].c ~= nil then
    -- do something
end

this condition throws the error: attempt to index a nil value

greatwolf
  • 20,287
  • 13
  • 71
  • 105
vitto
  • 19,094
  • 31
  • 91
  • 130

2 Answers2

3

You can use metamethods to check if your code is trying to access an undefined index. It is well documented on lua wiki.

With the following code the function check_main_index(t,k) will be called when action is defined to an index that is not defined. The function check_sub_index(t,k) is called when accessing a property that is not defined.

But the code you wrote works fine if action is defined to 'UP' and throws the error attempt to index a nil value only if action is defined to something else. (Tested with Lua 5.2).

action = 'UP'

local function check_main_index(t,k)
  print ( "main index : " .. k .. " does not exist" )
  return nil
end
local function check_sub_index(t,k)
  print ( "sub index : " .. k .. " does not exist" )
  return nil
end

frameActions = setmetatable({}, {__index = check_main_index})
frameActions['UP'] = setmetatable({ a = 1, b = 2 }, {__index = check_sub_index})

if frameActions[action].c ~= nil then
    print( "defined" )
else
    print( "not defined" )
end
A.G.
  • 1,279
  • 1
  • 11
  • 28
3

You can use some Lua magic and rewrite Etan Reisner's comment as

local E = {}
local my_val = ((frameActions or E).action or E).c
if my_val ~= nil then
    --your code here
end

This code checks if frameAction is nil aswell.

Explanation:

This is how lua will evaluate second line (consider that frameActions = {foo='bar'}):

(frameActions or E) --> {}, because frameAction is not nil or false and then will be take as result
(frameAction.action or E) --> E, because there is no 'action' key in frameAction table, so second 'or' argument is taken
E.c --> nil, because there is no 'c' key in empty table

Those 'check chains' could be even longer. For example:

local E = {}
local my_val = ((((foo or E).bar or E).baz or E).xyz or E).abc
if my_val ~= nil then
    --code if foo['bar']['baz']['xyz']['abc'] is not nil
end
wpedrak
  • 667
  • 7
  • 17
  • 1
    Hopefully I can speed up the next search by mentioning that this is called optional chaining. Some languages, like javascript and C#, support this using the `.?` operator, so that this would be `foo?.bar?.baz?.xyz?.abc`. It seems lua doesn't support that directly. We work around this by using `or` as a null-coalescing operator, and providing the empty table as the fallback at each step. – TamaMcGlinn Jan 16 '22 at 08:21