Skip to content

20. Closures, up values and other odd Lua creatures

April 1, 2013

Lua has some (to me) strange features, but they are powerful, so they are worth trying to understand. One of them is “closure”.

It took me an embarrassingly long time to understand this, and I’m hoping I can speed up that understanding for you.

Lexical scoping

First, let me get a definition out of the way, because it is used frequently in the same breath as closures. Lua is “lexically scoped”, which means that the scope of variables (how long they exist for, and which other code can see and use them) is restricted by where they are in the code and how they are defined. Local variables are a good example of lexical scoping.

So lexical scoping is just a phrase for the scoping rules you work with all the time, and we can pretty much ignore it from here.

Closures

Closures are a crazy feature of Lua. Just look at this example from the Lua manual.

function counter()
    local i=0
    return function()
        i=i+1
        return i
    end
end

function test()
    c=counter()
    print(c(),c(),c()). -- prints 1,2,3
    d=counter()
    print(d(),d()) --prints 1,2
end

The counter function sets local i=0, then returns a function rather than a value. This function is assigned to c, and calling c will run this function, so effectively
c() = function() i=i+1 return i end

There is nothing special about this, so far. Assigning a function to c is ok. However, you would expect to always get an error when you called c, because i is not defined inside the function, and the original i in counter has long since expired.

But you don’t. As you can see from the test function above, if you set c=counter(), and get the value of c three times, you will get 1,2,3, ie somehow counter is remembering i and adding 1 each time, even though i was a local variable and should have ceased when counter exited.

To make it even more confusing, if we set d equal to counter, that starts a completely separate counter going!

This is a special feature of Lua, called a closure. When you include an inner function inside an outer function, Lua allows the inner function to remember all the local variables from the outer function, and to keep remembering them indefinitely. These variables are known as up values, I guess because they come from the function above. So we have one upvalue, i, in counter.

And when you set d=counter(), Lua makes a completely separate copy of the local variables, which is why the counters c and d are not the same.

This approach is very similar to the “static” variable I am used to from Basic type languages, ie a local variable inside a function that keeps its value between calls to the function. But I think closures are better, because

  • you can restart the static variable by reinitialising the original function
  • you can have more than one copy of the variable, as shown above

So you can think of closures as a way of storing variables that may only be needed for a narrow purpose – such as counters – avoiding the need to use global variables that could accidentally get reused somewhere else in the code. If you think about it, there is absolutely no way any other code could get hold of, or change the value of i that is used in c, because the function counter that created it is long gone. So i is completely protected from interference, and only c can change it – and even c can only increase it by 1.

Here’s another example that shows a couple of other features of closures. Suppose we are doing calculations of screen positions as fractions of width and height, and when we actually want to draw on the screen, we need to turn those fractions into pixels. So we build this function:

--interpolates between min and max screen position, using frac (0-1)
function fracToPixels(min,max)
    return  function(frac) return min + (max-min)*frac end
end

It needs to first be set up with min and max. After that, the inner function will interpolate between min and max, given a fraction to use.

So we set up a converter function for x and y separately

pixelX=fracToPixels(1,WIDTH)
pixelY=fracToPixels(1,HEIGHT) 

Just looking at the X version, we pass through a min and max of 1 and WIDTH, and pixelX becomes

pixelX()=function(frac) return min + (max-min)*frac end

And, because the parameters passed to fracToPixels are used as upvalues for min and max, this effectively becomes

function(frac) return 1 + (WIDTH-1)*frac end

So we have customised the calculation to work specifically for the x coordinates. And we have a different customised version for the y coordinates.

We can test it like so, just passing through the fraction we want to use for x and y:

x=pixelX(0.3) --eg 225
y=pixelY(0.6) --eg 461

If you’re feeling brave, I’ll give you one more example. Closures don’t have to be functions inside functions. They can be functions inside anything, such as a for loop, do loop etc.

Suppose for example, we want to change the sin function to work with degrees instead of radians. Now I would probably just define a function called (say) sind and use that, but suppose you were hardcore and wanted to change the actual sin function.

We create the following code. Again, this is from the Lua manual.

do
    local oldsin=math.sin
    local factor=math.pi/180
    math.sin=function sin(x)
        return oldsin(x*factor)
    end
end

The do loop is there only to restrict the scope of all the local values to that small loop, and after copying the old sin function to a new variable (because we’ll need it later), and calculating a conversion factor from degrees to radians, we define a new math.sin function which takes one parameter, degrees, and returns the correct sin value, using the upvalues of the conversion factor and the old sin function.

What you can see from this is that functions (in this case oldsin) can also be upvalues.

Why on earth would you do this? The big benefit is that you prevent anyone accidentally getting hold of the original sin function, because once this code runs, that function becomes a hidden upvalue and can’t be accessed at all by users.

So to finish off, a closure is simply a function contained within a chunk of code. If you just want to do generic calculations like sin above, you might as well put the function in a do loop (or just anywhere in a function, if you aren’t so worried about restricting the scope of your local values). If, however, you need to initialise a particular version of the function, like a counter, or X or Y coordinates, you are better putting your closure inside a function, which makes it easier to initialise and assign a function to a variable.

A closure is good for hiding away parameters or factors that you don’t want interfering with other code. It’s almost like a miniature class, in a way.

I’m going to stop there, because I don’t know how well I’m doing with explaining this. If you want to give me feedback, send me a message (Ignatz) on the Codea forums or comment here.

Advertisement

From → Programming

9 Comments
  1. briarfox permalink

    Thanks for these tutorials, I am constantly checking your blog for new updates. Its been very helpful. I hope you keep these going. They are greatly appreciated!

  2. Doggynub permalink

    This was really helpful and helped me a lot. Great work man πŸ™‚

  3. hi there…
    I am actually find upvalues and closures quite confusing and I am still not quite understand how it works. This example below is taken from “Wrox Beginning Lua programming” book.

    function makelessthan (n)
    return function (x)
    return x
    end
    end

    lessthanfive = makelessthan (5)
    lessthanten = makelessthan (10)

    print (lessthanfive (4)) —-> print out 4, while

    function makelessthan (n)
    return function (x)
    return n
    end
    end

    lessthanfive = makelessthan (5)
    lessthanten = makelessthan (10)

    print (lessthanfive (4)) —-> print out 5

    how are these things actually work?
    I thought that “lessthanfive (4)” is actually “makelessthan (4)”
    so, the “x” will have the same value as “n” which is “4”

  4. Looking at the second example, the command

    lessthanfive = makelessthan (5)

    sends 5 through to makelessthan, so n becomes 5, and will stay 5 forever whenever you run lessthanfive, so now lesthanfive is effectively this function

    function lessthanfive(x)
    return 5 ‘because n=5
    end

    This means lessthanfive will always return 5 and will ignore whatever x you provide

    so lessthanfive (4)) ‘<— returns 5

    The first example is different, because it returns x, ie whatever you send to lessthanfive

    so lessthanfive (4)) '<— returns 4

  5. Thanks coolcodea for the quick reply. Really appreciate it very much. πŸ™‚
    I think I can understand this but still need to digest it much more,
    I came out with the example below :

    n = 5

    function mlt (n)
    return n
    end

    mls = mlt (12)

    print (n) —–> print out 5
    print (mls) —–> print out 12

    So can I conclude that this convention only applies for function within function?

    Thanks

    • So can I conclude that “this convention” only applies for function within function?
      p/s (“This convention” refers to the “makelessthan” function)

  6. It only applies to a function A that returns another function B, ie

    function A(x)
    return function() ..code.. end

    If it is hard to follow, I would leave it for now and come back to it later. Closures can be useful, but you can always do it another way, without them. So you can safely ignore them for now.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: