1. Integration with C (and C++ for that matter)
I have used a lot of languages during my short career as a programmer. Lisp, Scheme, Python, Perl, Bash, VBA, SQL, etc. etc. etc. There is no other language that I have ever used that even comes close to Lua when trying to commingle C code. The C API is so clean and so intuitive that I would argue that you could get up to speed on its use in an afternoon. Check out PIL's section on the C API if you are interested in learning more.
Why is this important? Well, for one this means that if you have an existing C (or C++) library, it is usually not very difficult to expose the API to Lua. Nor is it difficult to write a script in Lua and get something running on the C side. This also means that speed problems are rarely an issue in Lua programs. You can write something in Lua and truly rewrite it in C if it is a speed problem. It is always possible to rewrite something in C in other languages, but Lua is the only language in which I have found it easy to do so.
2. Speed and Simplicity
The standard Lua implementation performs extremely well compared to most other languages, even without writing anything in C. Perhaps this is because Lua uses a register based virtual machine rather than a stack based machine. Or it could simply be due to the fact that the programmers behind Lua are just very talented. Whatever the reason, you are rarely going to be overly concerned with performance when writing Lua code.
But, if you are not getting the results you would hope or expect, you can get an almost drop in replacement for the standard Lua implementation with LuaJIT. From the overview page:
LuaJIT is widely considered to be one of the fastest dynamic language implementations in existence ... with an unmatched low memory footprint: less than 125K for the VM plus less than 85K for the JIT compiler (on x86).
LuaJIT speeds can rival code written in C. And if you are still not getting the speed you want, see my 1st point above.
While not necessarily a language feature, I have found that using Lua has improved my general computer science knowledge over time. For example, this writeup on the implementation of Lua 5.0 gave me a very good overview of how virtual machines are implemented. Reading the very accessible source code, while following the recommended reading order suggested by Mike Pall (author of LuaJIT) has been eye opening as well. I don't think any of this would be possible except for the methodical manner in which Lua has evolved over time. This has allowed Lua to remain "Clean C" which means that it is easier for you to understand as a user of the language.
Lua provides you with functional programming constructs that make programming
more enjoyable. Examples include anonymous functions, higher order functions,
lexical closures, proper tail calls, etc. And this is not some superficial
gloss applied on top of the language - it represents some of the fundamental
underpinnings of the language itself. For example, all functions in Lua are
values (like the number 2 or the string "ktr") - and this means that every
function in Lua is anonymous. You simply attach a name to it so that you can
reference it later. Thus, like Roberto describes in his
book, you can reassign
print = math.sin
This type of functionality also enables you to build
sandboxes if you need them. If
5. Everything is a Table
Everything in Lua is a table. Arrays, hashes, "modules", the global
environment, etc. They are all tables. This means that you can
module (similar to Python's
import statement) and treat the resulting value
just like you would any other table. In Python, you might
some module and then the variables of the return value would be accessed like
vars(module). Not very difficult, but also not very Pythonic. In Lua, you
would access the variables in that module just like any other table
module[var]). I only mention Python to highlight differences - simply
showing that it may be easier to "hold Lua in your head" due to such
This has the added benefit of allowing you to learn the full Lua syntax faster than you could in most other languages. Without needing to worry about how lists are written versus how dictionaries, packages, etc. are written, you can "assume" you already know how they are written because you only need to know the one construct.
If you haven't figured it out already, Lua is a very consistent language.
A lot of time has gone into each and every feature to make sure that it was
done "just right". For example, Lua didn't have a
for loop until Lua 4.0 - 7
years after the first release. This was because
whileloops were more general. ... Also, we could not agree on a good syntax.
(See page 6 of this document). And since the authors of the language have remained relatively unchanged and rather limited (the Lua team does not like to accept patches), the language has evolved somewhat slowly and quite coherently. So you know features are well planned. (However, this also means you shouldn't expect to have a lot of your pet features implemented anytime soon.)
I won't go into a lot of detail, but rest assured that Lua runs on almost everything you can think of. The code is written as "Clean ANSI C", so if you have a compliant C runtime, you will likely be able to get Lua running without much fanfare.
All in all, a very powerful, yet simple language.