Lua Tutorials, Patterns, and Gems

This thread is intended for people who have at least a basic grasp of Lua already, but might now have read all of Programming in Lua or Lua Programming Gems. It will cover topics in such a way as to not only teach the reader how to use the feature or pattern in question, but to use it effectively in various real world situations.

CLOSURES -http://www.lua.org/pil/6.1.html

Usually when you say ‘function’ you usually mean a closure. A closure in Lua is a function in question plus all of the upvalues and such it needs. Here’s an example from Programming In Lua which will show this a bit better:

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

c = counter()
print(c()) – 1
print(c()) – 2
[/lua]

Woah. How does that work? i shouldn’t even exist in the returned function scope! This is an upvalue. When you return that anonymous function you’re not just returning a function. You’re returning a closure. A useful way of thinking of a closure in practical use is a function + all the local values of the scope that created it. For all functions a new closure is created so if you created a second counter there’d be a second i as well.

All right let’s move on to a potential use case a little more useful than a counter.

[lua]
function approach(value, goal, step)
return function(dt)
if value > goal then
value = value - step * dt
if math.min(value, goal) == value then
value = goal
return true, value
end
elseif value < goal then
value = value + step * dt
if math.max(value, goal) == value then
value = goal
return true, value
end
end

	return false, value
end

end

a = approach(0, 100, 1)
finished, val = a(dt) – false, 1 * dt

finished, val = a(dt) – true, 100
[/lua]

This function returns a function that takes a deltatime and approaches one value to another by a step over time and returns whether it is finished and it’s current value. The procedural implementation of this would be messy as hell to implement everywhere you used it, but now it’s all wrapped up in a nice closure. I suggest using closures for things that are mostly code and little data.

SIMPLE MEMOIZATION/WEAK TABLES

Here’s one a lot of you probably don’t know about. Weak tables. Read closures if you don’t know about them yet, because this one builds upon that.

For those of you who don’t know what memoization is it’s more or less trading memory for speed. It stores all of the past results of the function in a table for quick lookup.

[lua]
– do note this is not a very general implementation and only works with
– functions with a single argument and assumes the function has no side effects
– also untested, just serves as an example
function memoize(func)
local results = {}
setmetatable(results, {__mode = “v”})

return function(arg)
	if results[arg] then
		return results[arg]
	else
		results[arg] = func(arg)
		return results[arg]
	end
end

end

fastsin = memoize(math.sin)
fastsin(3) – executes a bit slower than math.sin the first call
fastsin(3) – executes an order of magnitude faster than math.sin the second call
[/lua]

So there’s a lot going on here. This function wraps the given function in a closure that memoizes said function. When the new function is called it either runs the first function with the given input or returns the saved value it has from a previous call. There’s more going on here, though. What’s with the call to setmetatable and __mode? What we’re doing here is making the table weak. This means that the garbage collector will collect values not in use whenever it runs. This makes it so recent calls are memoized, but memory isn’t wasted holding entries that aren’t often used.

OBJECT ORIENTATION

You guys probably all know the basics of object orientation in Lua. It’s not hard, just tables with functions inside. Due to the flexible nature of Lua tables there are tons of ways to object orient code. Here I’m going to present a few.

The simplest and most common:

[lua]
a = { value = 5, accountholder = “Joe” }

function account_withdraw(account, val)
account.value = account.value - val
end
[/lua]

This is a lot like it’s done in C. Tables are treated like data only types with functions that do work to them. This is great for simple things, but it makes hard to read/write code, and it doesn’t have a lot of great things a modern object system does. So let’s see where we can go from here…

[lua]
– modified example from Programming In Lua
Account = {}

Account.value = 0

function Account:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end

function Account:deposit(amount)
self.value = self.value + amount
end

a = Account:new()
a:deposit(50) – a.value == 50
[/lua]

This is a big step up. It uses metatables to make a prototype object available to the created table. This means that if the table doesn’t have a particular function/value it checks the metatable’s __index value for it. There are still some ways to improve on this though…

[lua]
Object = {}

function Object:init()
end

function Object:parent()
return getmetatable(self)
end

function Object:new(…)
local o = setmetatable({}, self)
self.__index = self
o:init(…)
return o
end
[/lua]

This is a quick wrapper for some basic metatable work I created very quickly. It’s simple and adds little overhead. I’m not saying you should use this particular implementation, it’s simply an example. Let me show you what this example makes simple that the above does not: inheritence.

[lua]
Cat = Object:new()
Cat.description = “cat”

function Cat:init() – This is called when “Cat:new()” is called with all of new’s arguments.
print “A " … Cat.description … " is born!”
end

Siamese = Cat:new() – Inheritence! (Also generates “A cat is born!”)
Siamese.description = “Siamese”

Joe = Siamese:new() – “A siamese cat is born!”
[/lua]

This allows for simple and easy creation of prototypes and inheritence chains. There are plenty of libraries available for this and many other types of OO on github. Check out middleclass!

To be continued…

I find this rather interesting, I think it’d be beneficial if you continued.

Awesome work. Something covering more advanced tables would be helpful as well.

Theoretically you could use something like math.sin = memoize(math.sin) as well as all of the other relatively heavy math functions to make them all a bit more effective for repeated calculations then, right?

Depends on what you’re calculating. If you’re calculating something like the sine of os.time() you’re going to just create a lot of garbage.

He’s right. A trick a lot of stuff uses on not-so-powerful hardware or where precision isn’t needed is rounding the number to like the second decimal digit. So x.xx and precalculating them all. It’s still a lot of memory, but it’s literally the cost of a table look up.

If you added logic to keep the input value between 0 and 2pi then it could work for any situation, for repeating functions at least.

There are like a few million possibilities between 0 and 2pi lol.

You missed my point

Keeping the input between 0 and 2pi would keep that lot of garbage from being created. And you could round to the nearest hundredth to narrow down those few million (actually infinite, not considering precision) possibilities