James
James

Reputation: 9278

Why does nil check fail

I am using Lua to query redis and want to check if a key isn't present but am confused as to why my code isn't working:

local bulk = redis.call("HMGET", KEYS[1], "p1", "p2")
for i, v in ipairs(bulk) do
    if (i == 1) then
        if (v == nil) then
            return nil  -- This is never entered
        end
    end
end

however the following code does work:

local bulk = redis.call("HMGET", KEYS[1], "p1", "p2")
for i, v in ipairs(bulk) do
    if (i == 1) then
        v = v or 0
        if (v == 0) then
            return nil  -- This does work
        end
    end
end

What is going on here?

Upvotes: 2

Views: 456

Answers (1)

Piglet
Piglet

Reputation: 28940

You're using ipairs to iterate over your table. The iteration will end at the first element that is nil. Hence v can never equal nil inside your for loop. So you'll never enter the if (v== nil) statement.

From the Lua Reference Manual 6.1 Basic Functions:

ipairs (t) Returns three values (an iterator function, the table t, and 0) so that the construction

 for i,v in ipairs(t) do body end

will iterate over the key–value pairs (1,t[1]), (2,t[2]), ..., up to the first nil value.

Actually you cannot use any of the standard iterators to find nil values.

If you only want to check if bulk[1] is nil:

Replace

local bulk = redis.call("HMGET", KEYS[1], "p1", "p2")
for i, v in ipairs(bulk) do
    if (i == 1) then
        if (v == nil) then
            return nil  -- This is never entered
        end
    end
end

with

local bulk = redis.call("HMGET", KEYS[1], "p1", "p2")
if not bulk[1] then return end

return and return nil are the same btw.

In case bulk[1] may be validly false check vs nil explicitly.

if bulk[1] == nil then return end

This code:

local bulk = redis.call("HMGET", KEYS[1], "p1", "p2")
for i, v in ipairs(bulk) do
    if (i == 1) then
        v = v or 0
        if (v == 0) then
            return nil  -- This does work
        end
    end
end

works because bulk[1] is either 0 or false in which case you replace it with 0.

A quick resarch confirms that you get false values instead of nil from the Redis Lua bindings. So using ipairs should be fine. You should just check if the value equals false, not nil.

Upvotes: 4

Related Questions