Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua : attempt to index a nil value; avoiding errors in conditionals

Let's say I have a giant table, something like:

test.test[1].testing.test.test_test

The table isn't guaranteed to exist. Neither are the tables containing it. I would like to just be able to do:

if test.test[1].testing.test.test_test then
   print("it exits!")
end

But of course, this would give me an "Attempt to index ? (a nil value)" error if any of the indices aren't yet defined. So many times, I'll end up doing something like this:

if test then
   if test.test then
      if test.test[1] then
         if test.test[1].testing then -- and so on

Is there a better, less-tedious way to accomplish this?

like image 695
Eli Bell Avatar asked Sep 08 '26 15:09

Eli Bell


2 Answers

You can avoid raising errors by setting an __index metamethod for nil:

debug.setmetatable(nil, { __index=function () end })
print(test.test[1].testing.test.test_test)
test = {test = {{testing = {test = {test_test = 5}}}}}
print(test.test[1].testing.test.test_test)

You can also use an empty table:

debug.setmetatable(nil, { __index={} })
like image 119
lhf Avatar answered Sep 13 '26 04:09

lhf


You can write a function that takes a list of keys to look up and does whatever action you want if it finds the entry. Here's an example:

function forindices(f, table, indices)
  local entry = table

  for _,idx in ipairs(indices) do
    if type(entry) == 'table' and entry[idx] then
      entry = entry[idx]
    else
      entry = nil
      break
    end
  end

  if entry then
    f()
  end
end

test = {test = {{testing = {test = {test_test = 5}}}}}

-- prints "it exists"
forindices(function () print("it exists") end,
           test,
           {"test", 1, "testing", "test", "test_test"})

-- doesn't print
forindices(function () print("it exists") end,
           test,
           {"test", 1, "nope", "test", "test_test"})

As an aside, the functional programming concept that solves this kind of problem is the Maybe monad. You could probably solve this with a Lua implementation of monads, though it wouldn't be very nice since there's no syntactic sugar for it.

like image 45
Asumu Takikawa Avatar answered Sep 13 '26 05:09

Asumu Takikawa