I am far from an expert at Lua, but I have done a couple of semi-serious projects in the language and will try to recall specifically what I didn't like:
- Broken lexical scoping: assignment acts as declaration, in effect clobbering global variables. Bad scoping is the single biggest source of bugs and confusion (
http://lua-users.org/lists/lua-l/2008-11/msg00008.html). Even simple variable access goes through table system, producing several L2 cache misses in process just to get to value. That makes Lua slower than comparable alternatives, like Lisp.
- Hash-Table as a primary data structure has overwhelming issues. There is no simple and safe way to implement Lisp-like FIRST and REST functions: either you have to copy whole Table or modify it, and sequential access is somewhat slow. There is no easy way to remove an element from a list. Even worse, the size of a list may not be what you expect: "b={};b[666]="a";print(#b)" will print 1. Table indexing starts from 1, instead of 0, like everything in computing. That acts as a source of errors and confusion, when interfacing with external APIs or converting algorithm from Lua to C/C++, while 0 still acts as a dangling pointer. Lua Tables don't provide advantages of immutable catenable queues - a silver bullet data structure, you'll find in modern Lisps and Haskell; Lua Tables are mutable and encourage modification, instead of creation, meaning there is no easy way to do functional programming with Lua. Lua's REPL wont pretty-print tables, instead it'll print something like "table: 0x807e978".
- Lua uses floating point values instead of integers, so 9999999999999999999==10000000000000000000. In general, Lua's logic seems odd: "nil+1" produces error, while "(not nil)+1" gives 2. Things could be unequal to itself: `t={[{1,2,3}]="abc"}; print(t[{1,2,3}])` wont print "abc", meaning that `{1,2,3} != {1,2,3}`.
- Lua' syntax is inconsistent and full of quirkness: underscores for special variables and cryptic symbols for simple functions, like `#xs` for `length(xs)` and `x = start,end,step` instead of range(start,end,step), while logical connectives (`and`, `or` in place of `&&`, `||`) are hard to notice between other symbols. do/then/end everywhere could be annoying. Moreover, `t = {"a","b","c"}; print(t[2])` works, but `print({"a","b","c"}[2])` fails. `print 'hello';` works, but `print 123;` fails.
- Lua is unstable: API changes frequently, functions are being added and deleted continuously, `table.foreach` being a good example of to be deleted function, and then there is `table.unpack`, which present only in some versions of Lua.
- Lua's GC is a naive mark-and-sweep implementation, which stores the mark bit directly inside objects, a GC cycle will thus result in all objects being written to, making their memory pages `dirty` and Lua's speed proportional to the number of allocated objects. Lua simply was not designed to support hundred thousand objects allocation per second.
- Lua was built as a glue language, and it shows. Much of Lua hype comes from it's usage as a simple integrated scripting language in video games industry. That makes typical Lua user a teenage gamer with little expectations or taste for computation features and productivity.