Metatables are sexy, but depending on the language you're coming from they may take a while to wrap your head around.
The first thing you need to realize is that Lua has one data structure - the table - and everything is an entry in a table. Functions, strings, everything.
So when you call a function, or look something up in an array, or whatever, you're actually telling Lua to look up a key value pair in a table. The neat thing is that with metatables you can tell Lua what to do if the key isn't found. You can either point it at a different table or alternatively a function.
This opens up all sorts of neat tricks. You can create a lookup table of English to German translations - and if you ever try to translate something that isn't in the table it can print an apology, display the untranslated string, and/or log an error to let the developers know they're missing a translation. Sure you can DO that in other languages, but you end up with messy branching conditionals. With Lua it's transparent.
Say you've got a table of translations called tranMsgs:
setmetatable(tranMsgs,tranFail)
tranFail.__index = function(t,k)
-- code goes here
end
Now whenever anyone tries to lookup a missing translation the above code will run. Very simple, very understandable.
You can also use metatables to cache complex calculations.
cachedResults = {}
setmetatable(cachedResults, expensiveFunction)
expensiveFunction.__index = function(t,k)
cachedResults.k = sqrt(sqrt(k^k))
return cachedResults.k
end
Now calling print(cachedResults[50]) will be much faster after the first time. And sure you can do that in any language, but it's brief, elegant, and easy to understand in Lua. :-)
If you're coming from a language like C or Java, getting your head around metatables will open the door to a lot of fun tricks.