Lua Five Two

lua-users home

Lua 5.2 is the latest major revision[1] of Lua following 5.1. This page has some information the mailing list during alpha/beta testing that may be out-of-date or incorrect. Official information and downloads on Lua 5.2 are at [].


While 5.1.x versions are strictly bug-fix only versions of 5.1[12][13][2], Lua 5.2 was allowed to make design changes that break full compatibility.


Background Information


Feel free to update references! (As well as anything else here.) -- AlexanderGladysh

TODO: Some sections below may need updated to reflect the final Lua 5.2.0 version.

Emergency garbage collector

Lua core forces a GC when allocation fails.


Generational garbage collector (optional and experimental)

Ephemeron tables

Tables with weak keys only visit value when key is accessible.


Userdata with finalizers

Userdata with finalizers are kept in a separated list for the GC


Non-string error messages

Lua interpreter better handles non-string error messages.


xpcall() improved

xpcall() now accepts arguments for the callback just like pcall() does



New function package.searchpath() to search for your files just like require() does.



Compile-time module system settings, available in package.config, are now documented.


__pairs and __ipairs

Loop iteration can be overloaded now with the help of new __pairs and __ipairs metamethods.

References: GeneralizedPairsAndIpairs


All types except string now respect __len metamethod. Previously, __len was not respected for table.


%q improved

string.format("%q") now escapes control characters.


Goto statement (includes simulating continue and labeled break statements)


Hexadecimal notation in string literals

You can write \xFF in strings in addition to old \255 notation.


Hexadecimal fractions and exponents in numerical literals

You can write numerical constants of the form 0x0.A or 0xA23p-4. In the latter case the 'p' indicates a binary exponent expressed in decimal (the manual does not make this clear: I assumed the exponent would be hexadecimal like the other parts). This feature is probably not useful in hand-written code but it allows precise de-serialisation of numbers serialised using the hexadecimal option of string.format.

However despite the inclusion of an official bit manipulation library, binary literals are still not supported.


Safer now allows ANSI C options only.



New luaL_testudata API function, similar to luaL_checkudata, but signaling invalid userdata to the caller rather than throwing an error.


Constant folding simplified

Division and modulo operations are no longer folded if the second argument is zero..


More freedom to yield()

Now you may yield() accross metamethods, for loop iterators pcall and xpcall calls and now-undocumented table.foreach[i] calls.

Also, C API calls are provided to implement your own yield-compliant C functions.

Bitwise operations module

Now you can manipulate bits in Lua without the help of 3rd party modules or patches. None of existing implementations was used though.



Now luaL_tolstring is documented. You may officially convert Lua values from C by the tostring() rules.

References: [20]

New functions: lua_tonumberx and luatointegerx


Lexical environments



getfenv() / setfenv() deprecated

getfenv() and setfenv() are deprecated in favor of the new lexical environments. Debug library counterparts are still there.


function/closure construction optimization

Cache anonymous functions/closures for reuse. This optimization is now possible with the removal of getfenv/setfenv. TODO:add better description and examples.


New loadin(env,chunk) function to load chunk in a given environment. Note that the chunk argument can also be a string.

fn,err = loadin({x=1,y=2},"return x+y")


load() chunk type filter

It is possible to forbid load()-ing of bytecode and/or source code chunks. Bytecode verification on load was removed.


Lua thread environment

Lua threads (a.k.a coroutines) no longer have separate environments.

References: (Anyone?)

ABI and bytecode incompatibility

As expected Lua 5.2 ABI and bytecode is incompatible with 5.1.


Deprecated features from 5.1

Almost all deprecated features from 5.1 were removed. New deprecated features are off by default.

References: (Anyone?)

Debug module no longer loaded by default

If you need it, require() it.

Assuming this refers to the debug library, it does not seem to be the case in the release version - the debug library is in the list loaded by luaL_openlibs. --JohnHind


Coroutine library promoted to a fully-fledged library

Previously the coroutine library was a sub-library loaded by the basic library loader function. In 5.2 it has been given its own loader function and promoted to a normal library. It is included in the list loaded by luaL_openlibs so this change is only important if your runtime does not use luaL_openlibs.

The manual has a slight error: this change is reflected in section 6, but section 6.2 still refers to it as "a sub-library of the basic library".


debug.getlocal parameter names

debug.getlocal gets parameter names of inactive functions. In debug.getlocal ([thread,] f, local), "The parameter f may also be a function. In that case, getlocal returns only the name of function parameters."


Upvalue manipulation

New functions to detect if two upvalues are the same and to join them together if they are not:


Additional debug info

debug.getinfo() and lua_getinfo() now return extra information about function on call stack:

References: (Anyone?)

Pattern: %f is documented

The frontier pattern is now documented.


Pattern: %g

New pattern %g represents all printable characters except space.

string.gsub repl

string.gsub [6] now raises an error if the replacement string contains a '%' followed by a character other than the permitted '%' or digit.

ipairs behaviour change (this feature has been retracted)

Now ipairs() iterates over #t elements of the table. In 5.1 it did until first nil.

References: Source code: lua-5.2.0-work4/src/lbaselib.c line 213

select() negative numbers

You may pass negative index to select() to get arguments from the end of the vararg (in the direct order).


math.log10() vs. math.log()

math.log10() is deprecated. Use 10 as new second argument of math.log().

References: (Anyone?)

table.maxn() removed

table.maxn is deprecated.


table.unpack() and table.pack()

unpack() is renamed to table.unpack(). table.pack() is added, packing arguments to a table and storing number of arguments to table's field "n".


Enhanced pipe support

If file was opened by io.popen(), file:close() returns process' exit code.


Better stopped GC handling

Calling collectgarbage("step") no longer restarts GC if it was stopped. Also, you may know if GC was stopped by calling collectgarbage("isrunning"). Of course you may do the same in C API.

References: (Anyone?)

Identifier's locale

Lua identifiers may no longer use locale-dependent characters.


New Registry fields

The following is a complete list of Lua's use of the registry table (at pseudo-index LUA_REGISTRYINDEX) in the 5.2.0 release.

Installed by lua_newstate

Installed by 'package' library loader

Installed by 'IO' library loader

The manual states: "As with global names, string keys starting with an underscore followed by uppercase letters are reserved for Lua." Note however that Lua does not rigerously follow this rule as with the "FILE*" key.

The metatable for strings has not been referenced in the registry, but it simply indexes the string library table itself, so functions added to that will automatically work as methods of string objects.


Light C functions / lua_cpcall improvements

lua_pushcfunction no longer allocates. This is more efficient and doesn't raise on failure. It also eliminates the need for lua_cpcall(), which has been removed from the API. Furthermore, a version of lua_cpcall supporting multiple arguments and return values is no longer needed either since lua_pcall now can do this.


If you need one, use LUA_RIDX_GLOBALS from the registry (or LUA_ENVIRONINDEX if you didn't changed your C function environment).

References: (Anyone?)

lua_getglobal(), lua_setglobal(), and lua_register()

These functions work with C function environment instead of state's global environment to better reflect the way Lua works with global variables.

References: (Anyone?)

luaL_typerror() deprecated



New function lua_compare() was added to replace deprecated lua_equal() and lua_lessthan().



New function lua_arith() to do arithmetics with Lua values the way Lua does it.


Object length from C

lua_objlen() was renamed to lua_rawlen(). lua_len() was added to honor __len metamethod.


lua_checkstack() updated

lua_checkstack is now only returns error codes (never raises). Use luaL_checkstack if you want to raise (with error string).


lua_pushstring() and lua_pushlstring() enhanced

Now they return pointers to the internal string representations.

References: (Anyone?)


Allows to copy Lua values on stack (replacing existing value in the target slot).


Lua runtime version checks

Two new functions were added, lua_version() and luaL_checkversion() to let user check runtime versions and address space correctness. This would help to prevent dreaded obscure bugs when several Lua instances are linked to the executable. luaL_checkversion() is called from luaL_register(), so such checks would be performed automatically when most modules are require()-d.



New function to produce stacktraces just like debug.traceback() does.



LUA_ERRGCMM is a new runtime error code to signify error in __gc metamethod. LUA_OK was added to keep symmetry and means that all went OK and there were no errors.


Better dynamic library loading on *nix

Now Lua C modules may load dynamic libraries with global symbols (thanks to RTLD_GLOBAL).

References: (Anyone?)

Dynamic library loading on Windows improvements

DLL search path handling was improved on Windows.

More constants per chunk

Maximum number of constants per chunk increased to 2^26 from 2^18. Go, huge table dumps!


Parser optimizations

Parser eats less c-stack space as it no longer uses auto arrays.


New floating point hash function

New hash function for floating point values to better handle cases when lua_Number is defined as long double on some 64-bit platforms.


file:write() improved

file:write() returns file to allow chained calls.


end-of-line character preservation in new file:read end file:lines

A new "*L" option to file:read is like "*l" but keeps end of line (if present). Also, a new keepNL argument in file:lines keeps new lines.

os.exit() improved

It may optionally call lua_close() on the Lua state.


os.execute() interface change

"Function os.execute now returns true when command terminates successfully and nil plus error information otherwise." [10]


$ lua51 -e "os.exit(3)"; echo $?
$ lua51 -e 'print(os.execute[[lua -e "os.exit(3)"]])'
$ lua52  -e 'print(os.execute[[lua -e "os.exit(3)"]])'
nil	exit	3
$ perl -e 'print(system(qq(perl -e "exit(3)")),"\n")'
$ python -c "import os; print(os.system(\"python -c 'import os; os._exit(3)'\"))"

CallInfo stack now is a linked list



Resolve module system and module function issues

The module/luaL_register functions are deprecated and replaced by luaL_newlib and luaL_setfuncs. There is also a new function luaL_requiref.

I believe this is a much more significant change than the manual or other material suggest. On the face of it, where you could previously write require 'coroutine' for example, you now have to write coroutine = require 'coroutine'. This is definitely a useful improvement, but if I have understood it correctly, it will break a lot of existing code. The 'changes' section of the manual is not sufficiently explicit about this. Worse, the documentation for require does not clearly state the purpose of the return value. You have to read between the lines that the intent is to return either the module's global table or the value 'true' if the module does not export a global table (delivering this intent depends on the module loader following some rules, which are not explicitly stated).

The manual says "Once a loader is found, require calls the loader with two arguments: modname and an extra value dependent on how it got the loader. [...] If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname]." How is that not clear? One thing, I might add, however, is that allowing true, rather than a module table, to be assigned to package.loaded[modname] is normally something to be avoided and is rather a fallback behavior, lacking any better value to use, to at least ensure that the module loader isn't executed more than once on multiple require calls. Now, concerning exactly what the loader should return, it should normally be a table [21], but the official Lua reference manual might be silent on this because of the MechanismNotPolicy design principle. Sometimes module loaders return functions (normally object constructors), though perhaps it would be preferable to return FuncTables (i.e. a table with a call operator) since it's quasi-standard for require'foo'._VERSION to represent the module version (ModuleVersioning), which remains possible with FuncTables. BTW, the module function, though deprecated in 5.2, is still available unless you turn off deprecated features, and the call to module sets package.loaded[modname] (as well as a global). --DavidManura

Compare luaL_requiref (C API) with require (Lua): the latter just takes the module name, while the former takes the module name, the library loader function and a flag which you set 'true' to store the return from the loader function in a global with the same name as the library. luaL_openlibs uses luaL_requiref with this flag set. Hence it will open the standard libraries with their global tables initialised as expected. However libraries opened from Lua with require must set the global explicitly using the returned value.

Please feel free to correct the above two paragraphs if they are misconceived!

luaL_requiref I consider to be just a convenience function for certain cases like linit.c. For example, it assumes the loader is a C function (lua_CFunction) and the destination table is LUA_RIDX_GLOBALS, so it's not entirely general. The "must set the global explicitly" is not really true since it's normally preferred to set a local explicitly, local foo = require 'foo', which doesn't tamper with _G. --DavidManura

Sorry DavidManura, I did not really intend to open a policy discussion/critique, just to warn others about a practical problem I just discovered the hard way. My runtime does not load most of the standard libraries by default but instead puts their loader functions in the preloads table (I do this to save RAM). After converting from 5.1.4 to 5.2 I found that Lua with e.g. require 'coroutine' no longer worked and I had to change it to coroutine = require 'coroutine'. This leads to the consideration that, if third-party library developers follow the example (I will not say policy) set by the standard libraries, then they too may break existing Lua code. Most users will not notice this change with respect to the standard libraries because runtimes usually load these by calling luaL_openlibs which in turn calls luaL_requiref. -- JohnHind


Version-specific environment variables

Added environmented variables LUA_PATH_5_2, etc.

What we wouldn't get in 5.2

...Or would we?

You're welcome to put your pet feature here, assuming it was supported by someone else on the list AND was declined by Lua authors for inclusion into 5.2. Please be polite. --AlexanderGladysh


Something along the lines of struct/lpack


Decline motivation: (Have a link?)

Token filters

Or other "meta" facility.


Decline motivation: (Have a link?)

#line directive

This would be similar to the C preprocessor's #line directive [11]. The main motivation is to allow preprocessors to output this in generated Lua code so that debugging line numbers and file names correspond to the original (prior to preprocessing) source code.

Removal of automatic coercions

lua_rawtostring / rawtostring

Get a string without coercions from numbers.


Decline motivation: (Have a link?)

Hyphens in module names

Module version number is currently expected to be on the left side of the name, which is rather unusual.


Decline motivation: (Have a link?)

Improving deterministic resource cleanup

Replace package.seeall with something like package.clean

Replace package.seeall with something analogous to the package.clean solutions in ModuleDefinition, but updated to support _ENV. package.seeall doesn't separate the public module table with the private implementation environment.



Some features/changes proposed by users for 5.2 are listed in FeatureProposals. Requests should be posted to the mailing list.

See Also

RecentChanges · preferences
edit · history
Last edited May 20, 2012 2:00 am GMT (diff)