Lua vs. Python
Contents
Lua has a simpler and more elegant design than Python.
It starts by having a small type system. There are only eight core types in Lua nil, boolean, number, string, userdata, function, thread and table. See http://www.lua.org/pil/2.html a minimal type system keeps the implementation simple and efficient.
The only complex data structure in Lua is a table. They have a dual nature as a hash table or an array depending on how they are used. Tables are the foundation of everything in Lua. A Lua program is stored in memory as a Lua table. Each program function is an entry in this table. To implement objects in Lua you use tables. It is similar to the way javascript objects are constructed.
Python has a very large built in type system. It has objects that represent dates, arrays, tables, slice objects, objects etc. That type system is not static either. It keeps on growing with successive releases of Python. All that adds up to a lot of surface area and complexity.
Lua was built for portability and is designed to have a small foot print. The standard library is small and has clean interfaces. Lua does not include a Regex library since:
Unlike several other scripting languages, Lua does not use POSIX regular expressions (regexp) for pattern matching. The main reason for this is size: A typical implementation of POSIX regexp takes more than 4,000 lines of code. This is bigger than all Lua standard libraries put together. In comparison, the implementation of pattern matching in Lua has less than 500 lines. Of course, the pattern matching in Lua cannot do all that a full POSIX implementation does. Nevertheless, pattern matching in Lua is a powerful tool and includes some features that are difficult to match with standard POSIX implementations.
In practice the Lua string matching library does everything required for transformation code. It is compact, powerful and unicode compatible. Having this standard pattern matching library built into Lua is a big advantage.
Lua’s C APIs reflect its internal design. The Lua API is very small and well thought compared to Python. One is never given a reference to a Lua object. This is different to most scripting language APIs like JNI and Python that give reference counted pointers to internal objects. Instead all interaction with the Lua virtual machine is done via a virtual “Stack” – all the operations involve pushing and pulling values off this stack. It is safe by design.
Lua has very few external dependencies. The core is very small. Python pulls in a heap of external libraries. It is impossible to run a Python interpreter without linking in a lot of libraries and including many core Python library files. Upgrading Python is a difficult exercise – in my experience it takes 2-3 weeks to apply all the patches, tweak the various flags and switch off undesired behavior to install a new version of Python.
Lua is built for efficiency. Whereas Python, for purity, reference counts the Python “None” object which is equivalent to nil in Python. This is something that has caused headaches for us in the past.
Lua interpreters are completely independent. There are no issues with running independent Lua interpreters on separate threads. This is in contrast to the GIL for Python.
Lua has an extremely clean simple design and a small API. I think this is the reason that it has the world’s fastest JIT implementation for a dynamic scripting language. Lua is extremely popular within the gaming market because of its speed (see also speed compared to python).
One of the challenges moving forward with Python is that Python 3.0 is not backwards compatible with Python 2.x. So we were faced with an unpleasant situation of needing to figure out how to support two versions of Python. This is not something that anyone is likely to thank us for.
Fortunately by going down this route we can freeze our Python support, we will continue supporting and patching – but no big changes will be made. Which is ideal since no one likes to rewrite interfacing code.