Question

I'm having trouble understanding the following. I have the following code:

awful.key({ "Mod1" }, "Tab",
    function (c)
        local grabber = awful.keygrabber.run(
            function(mod, key, event)
                if grabber == nil then
                    naughty.notify({ text="nope"})
                end
                awful.keygrabber.stop(grabber)
                return
            end)
    end)

This is supposed to grab the keyboard when I press super+Tab then release keyboard focus by calling the stop method. However the grabber variable appears to be nil. At first I thought this was a scope problem, so I removed the local, this works. However I have the feeling as if this isn't the way to solve this problem.

After messing around with it I found out this works:

awful.key({ "Mod1" }, "Tab",
    function (c)
        local grabber
        grabber = awful.keygrabber.run(
            function(mod, key, event)
                if grabber == nil then
                    naughty.notify({ text="nope"})
                end
                awful.keygrabber.stop(grabber)
                return
            end)
    end)

The only difference is that the variable grabber is defined on one line and is assigned one line later. Why can't I do this on the same line?

Was it helpful?

Solution

In the statement

local a = expr

where expr can be any Lua expression, the local a is only created after the expression has been evaluated. Before that, the local a does not exist. If the expression uses a variable called a, the variable is taken from the next "level" up. See section 2.6 of the Lua ref, it is short and provides additional insight into this. But what it means is that if you have

a = 123
local b = 456
local c = c + b

the third line will fail to execute because the c on the right side of the = does not yet exist so it is nil. The b does exist, although it is a local. Similarly, in

local a = f()

if f() uses a, Lua will look for an a that is above that line since it has not yet created a local a. If there is none above, a will be nil, regardless of how many times the function is run:

do 
    local a = 1
    function g() a=a+1 end -- modifies the above local a ("upvalue")

    local a = function() return a+1 end -- a+1 uses the first local a
    -- a is now a local function, using the first local a 

    print(a()) -- prints 2
    g() -- increases the external a
    print(a()) -- prints 3
end

So where the local is declared in relation to the functions that use them is critical, and a local doesn't exist (even a local that "hides" a previous local) until the expr is fully evaluated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top