<<
Home , PHP

contributed articles

DOI:10.1145/3186277 build a new abstraction. Encapsu- Simplicity, small size, portability, lation in the language provides a good example of a policy. The ISO C and embeddability set Lua apart specification offers no mechanism from other scripting languages. for modules or interfaces.9 Neverthe- less, C leverage existing BY ROBERTO IERUSALIMSCHY, LUIZ HENRIQUE DE FIGUEIREDO, mechanisms (such as file inclusion AND WALDEMAR CELES and external declarations) to achieve those abstractions. On top of such ba- sic mechanisms provided by the C lan- guage, policy adds several rules (such as “all global functions should have a A Look at prototype in a header file” and “header files should not define objects, only de- clare them”). Many programmers do not know these rules (and the policy as a whole) are not part of the C language. the Design Accordingly, in the design of Lua, we have replaced addition of many different features by creating instead only a few mechanisms that allow of Lua programmers to implement such fea- tures themselves.6 The motto leads to a design that is economical in con- cepts. Lua offers exactly one general mechanism for each major aspect of programming: tables for data; func- tions for abstraction; and LUA IS A developed at the Pontifical for control. On top of these building Catholic University of Rio de Janeiro (PUC-Rio) that blocks, programmers implement sev- eral other features, including modules, has come to be the leading scripting language for objects, and environments, with the video games worldwide.3,7 It is also used extensively in aid of minimal additions (such as syn- sugar) to the language. Here, we embedded devices like set-top boxes and TVs and in look at how this motto has worked out other applications like Adobe Photoshop Lightroom in the design of Lua. and .14 Its first version was released in 1993. Design Goals The current version, Lua 5.3, was released in 2015. Like other scripting languages, Lua Though mainly a procedural language, Lua lends has dynamic types, dynamic data struc- itself to several other paradigms, including object- tures, garbage collection, and an - like functionality. Consider Lua’s par- oriented programming, , and ticular set of goals: data-driven programming.5 It also offers good support for data description, in the style of JavaScript and key insights ˽˽ What sets Lua apart from other scripting JSON. Data description was indeed one of our main languages is its particular set of goals: motivations for creating Lua, some years before the simplicity, small size, portability, and embeddability. appearance of XML and JavaScript. ˽˽ The entire implementation of Lua has Our motto in the design of Lua has always been 25,000 lines of C code; the binary for 64-bit has 200k bytes. “mechanisms instead of policies.” By policy, we mean ˽˽ Since its inception, Lua was designed

a methodical way of using existing mechanisms to to interoperate with other languages. BUG FISH BY IMAGE

114 COMMUNICATIONS OF THE ACM | NOVEMBER 2018 | VOL. 61 | NO. 11 NOVEMBER 2018 | VOL. 61 | NO. 11 | COMMUNICATIONS OF THE ACM 115 contributed articles

Simplicity. Lua aims to offer only a access global variables in a state, and of embeddability in the design of Lua, few powerful mechanisms that can ad- perform other tasks. The stand- we first briefly introduce the dress several different needs, instead alone Lua is a tiny applica- between Lua and its host language. of myriad specific language constructs, tion written on top of the . each tailored for a specific need. The These goals have had a deep impact The Lua–C API Lua reference manual is small, with on our design of Lua. Portability re- To illustrate the concept of embedding approximately 100 pages covering the stricts what the standard libraries can in Lua, consider a simple example of a language, its standard libraries, and offer to what is available in ISO C, in- C program using the Lua library. Take the API with C; cluding date and time, file and string this tiny Lua script, stored in a file Small size. The entire implementa- manipulation, and basic mathemati- tion of Lua consists of 25,000 lines of cal functions. Everything else must be pi = 4 * math.atan(1) C code; the binary for 64-bit Linux has provided by external libraries. Simplic- 200k bytes. Being small is important ity and small size restrict the language Figure 1 shows a C program that runs for both portability, as Lua must fit into as a whole. These are the goals behind the script and prints the value of pi. a system before running there, and em- the economy of concepts for the lan- The first task is to create a new state bedding, as it should not bloat the host guage. Embeddability has a subtler and populate it with the functions from application that embeds it; influence. To improve embeddability, the standard libraries (such as math. Portability. Lua is implemented in Lua favors mechanisms that can be atan). The program then calls luaL _ ISO C and runs in virtually any system represented naturally in the Lua-C API. loadfile to load (precompile) the with as little as 300k bytes of memory. For instance, Lua tries to avoid or re- given source file into this state. In the Lua runs in all mainstream systems duce the use of special syntax for a new absence of errors, this call produces a and also on mainframes, inside OS ker- mechanism, as syntax is not accessible Lua function that is then executed by nels (such as the NetBSD kernel), and through an API. On the other hand, lua _ pcall. If either loadfile or on “bare metal” (such as NodeMCU mechanisms exposed as functions are pcall raises an error, it produces an running on the ESP8266 microcon- naturally mapped to the API. error message that is printed to the troller); and Following the motto “mechanisms terminal. Otherwise, the program gets Embeddability. Lua was designed instead of policies” has a clear impact on the value of the pi and since its inception to interoperate with simplicity and small size. It also affects prints its value. other languages, both by extending— embeddability by breaking complex The data exchange among these API allowing Lua code to call functions concepts into simpler ones that are calls is done through an implicit stack written in a foreign language—and by easier to represent in the API. in the Lua state. The call to luaL _ embedding—allowing foreign code to Lua supports eight data types: nil, loadfile pushes on the stack either call functions written in Lua.8 Lua is boolean, number, string, userdata, a function or an error message. The thus implemented not as a standalone table, function, and , which rep- call to lua _ pcall pops the func- program but as a library with a C API. resents coroutines. The first five are tion from the stack and calls it. The This library exports functions that cre- no surprise. The last three give Lua call to lua _ getglobal pushes the ate a new Lua state, load code into a its flavor and are the ones we discuss value of the global variable. The call to state, call functions loaded into a state, here. However, given the importance lua _ tonumber projects the Lua val- ue on top of the stack to a double. The Figure 1. A C program using the Lua library. stack ensures these values remain vis- ible to Lua while being manipulated by #include #include “lauxlib.h” the C code so they cannot be collected #include “lualib.h” by Lua’s garbage collector. Besides the functions used in this int main (int argc, char **argv) { simple example, the Lua–C API (or “C // create a new state lua_State *L = luaL_newstate(); API” for short) offers functions for all // load the standard libraries kinds of manipulation of Lua values, luaL_openlibs(L); including pushing C values (such as // try to load the given file and then // call the resulting function numbers and strings) onto the stack, if (luaL_loadfile(L, argv[1]) != LUA_OK || calling functions defined by the script, lua_pcall(L, 0, 0, 0) != LUA_OK) { and setting variables in the state. // some error occurred; print the error message fprintf(stderr, “lua: %s\n”, lua_tostring(L, -1)); } Tables else { // code ran successfully “Table” is the Lua term for associa- lua_getglobal(L, “pi”); tive arrays, or “maps.” A table is just printf(“pi: %f\n”, lua_tonumber(L, -1)); a collection of entries, which are pairs } lua_close(L); // close the state 〈key, value〉. return 0; Tables are the sole data-structuring } mechanism in Lua. Nowadays, maps are available in most scripting

116 COMMUNICATIONS OF THE ACM | NOVEMBER 2018 | VOL. 61 | NO. 11 contributed articles languages, as well as in several non- An interesting property of this im- scripting ones, but in Lua maps are plementation is that it gives sparse ubiquitous. Indeed, Lua programmers arrays for . For instance, when a use tables not only for all kinds of data creates a table with three structures (such as records, arrays, entries at indices 5, 100, and 3421, Lua lists, sets, and sparse matrices) but Lua offers exactly automatically stores them in the hash also for higher-level constructs (such as one general part, instead of creating a large array modules, objects, and environments). with thousands of empty slots. Programmers implement records mechanism for Lua also uses tables to implement using tables whose indices are strings each major aspect weak references. In languages with representing field names. Lua sup- garbage collection, a is ports records with , of programming: a reference to an object that does not translating a field reference like t.x to prevent its collection as garbage.10 In a table-indexing operation t[“x”]. tables for data; Lua, weak references are implemented Lua offers constructors, expressions functions for in weak tables. A weak table is thus a that create and initialize tables. The table that does not prevent its contents constructor {} creates an empty table. abstraction; and from being collected. If a key or a value The constructor {x=10,y=20} creates coroutines for in an entry is collected, that entry is a table with two entries, one mapping simply removed from the table; we dis- the string "x" to the integer 10, the control. cuss later how to signal that a table is other mapping "y" to 20. Program- weak. Weak tables in Lua also subsume mers see this table as a record with ephemerons.4 fields "x" and "y". Weak tables seem to contradict the Programmers implement arrays motto “mechanisms instead of poli- with tables whose indices are positive cies” because weak reference is a more integers. Constructors also support basic concept than weak table. Weak this usage. For example, the expression tables would then be a policy, a particu- {10,20,30} creates a table with three lar way of using weak references. How- entries, mapping 1 to 10, 2 to 20, and 3 ever, given the role of tables in Lua, it to 30. Programmers see the table as an is natural to use them to support weak array with three elements. references without introducing yet an- Arrays have no special status in the other concept. of Lua; they are just ordi- nary tables. However, arrays pervade Functions programming. Therefore, implemen- Lua supports first-class anonymous tation of tables in Lua gives special functions with lexical scoping, infor- attention to their use as arrays. The in- mally known as closures.13 Several non- ternal representation of a table in Lua functional languages nowadays (such has two parts: an array and a hash.7 If as Go, Swift, Python, and JavaScript) the array part has size N, all entries offer first-class functions. However, to with integer keys between 1 and N are our knowledge, none uses this mecha- stored in the array part; all other en- nism as pervasively as Lua. tries are stored in the hash part. The All functions in Lua are anonymous. keys in the array part are implicit and This is not immediately clear in the do not need to be stored. The size N of standard syntax for defining a function the array part is computed dynamical- ly, every time the table has to rehash function add (x, y) as the largest power of two such that return x + y at least half the elements in the array end part will be filled. A generic access (such as t[i]) first checks whether i Nevertheless, this syntax is just syn- is an integer in the range [1, N ]; this tactic sugar for an assignment of an is the most common case and the one to a variable programmers expect to be fast. If so, the operation gets the value in the ar- add = function (x, y) ray; otherwise, it accesses the hash. return x + y When accessing record fields (such end as t.x) the Lua core knows the key is a string and so skips the array test, go- Most dynamic languages offer some ing directly to the hash. kind of eval function that evaluates a

NOVEMBER 2018 | VOL. 61 | NO. 11 | COMMUNICATIONS OF THE ACM 117 contributed articles

piece of code produced at runtime. In- Figure 2. A simple module in Lua. Statically, a module is simply the stead of eval, Lua offers a load func- chunk that creates its corresponding tion that, given a piece of , local M = {} table. Figure 2 shows a standard idiom

returns a function equivalent to that function M.new (x, y) for defining a simple module in Lua. code. We saw a variant of load in the C return {x = x, y = y} The code creates a table in the local API in the of luaL _ loadfile. end variable M, populates the table with Consider the following piece of code some functions, and returns that table. function M.add (u, v) return M.new(u.x+v.x, u.y+v.y) Recall that Lua loads any chunk as the local id = 0 end body of an enclosing anonymous func- function genid () tion; this is how one should read that id = id + 1 function M.norm (v) code. The variable M is local to that return math.sqrt(v.x^2 + v.y^2) return id end enclosing function and the final state- end ment returns from that function. return M Once defined in a file mymodule. When one loads it, the function lua, a programmer can use that mod- load returns an anonymous function ule with code like thisa equivalent to the following code Figure 3. A module in Lua using environments. local vec = require “mymodule”

function () local sqrt = math.sqrt print(vec.norm(vec.new(10, 10))) local id = 0 local _ENV = {} --> 14.142135623731 function genid () function new (x, y) id = id + 1 return {x = x, y = y} In it, require is a regular func- return id end tion from the standard library; when end the single argument to a function is a function add (u, v) end return new(u.x+v.x, u.y+v.y) literal string, the code can omit the pa- end rentheses in the call. If the module is

So, if a programmer loads Lua code function norm (v) not already loaded, require searches stored in a string and then calls the re- return sqrt(v.x^2 + v.y^2) for an appropriate source for the given sulting function, the programmer gets end name (such as by looking for files in a

the equivalent of eval. return _ENV list of paths), then loads and runs that We use the term “chunk” to denote code, and finally returns what the code a piece of code fed to load (such as a returns. In this example, require re- source file). Chunks are the compila- nisms in Lua, including modules, turns the table M created by the chunk. tion units of Lua. When a programmer object-oriented programming, and Lua leverages tables, first-class func- uses Lua in interactive mode, the Read- . We now discuss tions, and load to support modules. Eval-Print Loop (REPL) handles each some of them, emphasizing how they The only addition to the language is the input line as a separate chunk. contribute to Lua’s design goals. function require. This economy is The function load simplifies the Modules. The construction of mod- particularly relevant for an embedded semantics of Lua in two ways: First, un- ules in Lua is a nice example of the language like Lua. Because require is like eval, load is pure and total; it has use of first-class functions and tables a regular function, it cannot create lo- no side effects and it always returns a as a basis for other mechanisms. At cal variables in the caller’s scope. Thus, value, either a function or an error mes- runtime, a module in Lua is a regular in the example using "mymodule", the sage; second, it eliminates the distinc- table populated with functions, as well programmer had to define explicitly tion between “global” code and “func- as possibly other values (such as con- the vec. Yet this limita- tion” code, as in the previous chunk stants). Consider this Lua fragment tion gives programmers the ability to of code. The variable id, which in the give a local name to the module. original code appears outside any func- print(math.sin(math.pi/6)) On the one hand, the construction tion, is seen by Lua as a local variable --> 0.5 of modules in Lua is not as elegant in the enclosing anonymous function as a dedicated language mechanism representing the script. Through lexi- Abstractly, programmers read this could be, with explicit import and ex- cal scoping, id is visible to the func- code as calling the sin function from port lists and other refinements, as in tion genid and preserves its value be- the standard math module, using the the “import machinery” in Python.12 tween successive calls to that function. constant pi from that same module. On the other hand, this construction Thus, id works like a in Concretely, the language sees math as has a clear semantics that requires no C or a class variable in . a variable (created when Lua loaded its standard libraries) containing a refer- Exploring Tables and Functions ence to a table. That table has an entry a To test these pieces of code interactively, remove the local from the variable initializations. In Despite their apparent simplicity—or with the key "sin" containing the sine interactive mode, Lua loads each line as an in- because of it—tables and functions function and an entry "pi" with the dependent chunk. A local variable is thus visible form a basis for several other mecha- value of π. only in the line where it was defined.

118 COMMUNICATIONS OF THE ACM | NOVEMBER 2018 | VOL. 61 | NO. 11 contributed articles further explanation. It also has an inex- environment. All chunks thus share fines the module components directly pensive implementation. Finally, and this same environment by default, giv- as free variables; instead of M.norm, it also quite important, it has an easy in- ing the illusion of global variables; in uses only norm, which Lua translates tegration with the C API: One can eas- the chunk just mentioned, both v and to _ E N V.n or m . The code ends the ily create modules in C; create mixed print refer to fields in that table and module with return _ ENV. modules with some functions defined thus behave as global variables. Howev- This method for writing modules in Lua and others in C; and for C code er, both load and the code being load- has two benefits: First, all external call functions inside modules. The API ed can modify _ ENV to any other value. functions and modules must be ex- needs no additional mechanisms to do The _ ENV mechanism allows different plicitly imported right at the start; and these tasks; all it needs is the existing scripts to have different environments, second, a module cannot pollute the Lua mechanisms to manipulate tables functions to be called with different en- global space by mistake. and functions. vironments, and other variations. Object-oriented programming. Environments. Local variables in The translation of free variables Support for object-oriented program- Lua follow a strict lexical scoping disci- needs semantic information to deter- ming in Lua follows the pattern we pline. A local variable can be accessed mine whether a variable is free. Never- have been seeing in this article: It tries only by code that is lexically written in- theless, the translation itself is purely to build upon tables and functions, side its scope. Lexical scoping implies syntactical. In particular, _ ENV is a adding only the minimum necessary that local variables are one of the few regular variable, needing no special to the language. constructions that do not cross the C treatment by the . The pro- Lua uses a two-tier approach to API, as C code cannot be lexically in- grammer can assign new values to object-oriented programming. The side Lua code. _ ENV or declare other variables with first is implemented by Lua and the A program in Lua can be composed that name. As an example, consider second by programmers on top of the of multiple chunks (such as multiple this fragment first one. The first tier is class-based. modules) loaded independently. Lexi- Both objects and classes are tables, cal scoping implies that a module do and the relation “instance of” is dy- cannot create local variables for other local _ ENV = {} namic. Userdata, which represents C chunks. Variables like math and re- ... values in Lua, can also play the role of quire, created by the standard librar- end objects. Classes are called metatables. ies, should thus be created as global In this first tier, a class can define only variables. However, using global vari- Inside the do block, all free vari- methods for the standard operators ables in a large program can easily ables refer to fields in the new table (such as addition, subtraction, and lead to overly complex code, entan- _ ENV. Outside the block, all free vari- concatenation). These methods are gling apparently unrelated parts of a ables refer to the default environment. called metamethods. program. To circumvent this conflict, A more typical use of _ ENV is for Figure 4 illustrates how a program- Lua does not have global variables writing modules. Figure 3 shows how mer would use this basic mechanism built into the language. Instead, it to the simple module of Figure to perform arithmetic on 2D vectors. offers a mechanism of environments 2 using environments. In the first line, The code starts with a table mt that that, by default, gives the equivalent where the code “imports” a function would be the metatable for the vec- of global variables. Nevertheless, as we from the math module, the environ- tors. The code then defines a function show later in this article, environments ment is still the default one. In the newVector to create 2D vectors. Vec- allow other possibilities. second line, the code sets the envi- tors are tables with two fields, x and y. Recall that any chunk of code in Lua ronment to a new table that will rep- The standard function setmetatable is compiled as if inside an anonymous resent the module. The code then de- establishes the “instance of” relation function. Environments add two sim- ple rules to this translation: First, the Figure 4. An example of metatables. enclosing anonymous function is com- local mt = {} piled as if in the scope of a local vari- able named _ ENV; and second, any function newVector (x, y) free variable id in the chunk is trans- local p = {x = x, y = y} setmetatable(p, mt) lated to _ E N V.id . For example, Lua return p loads the chunk print(v) as if it was end written like this function mt.__add (p1, p2) return newVector(p1.x + p2.x, p1.y + p2.y) local _ ENV = <> end return function () _ E N V.pr i nt( _ E N V.v) -- example of use A = newVector(10, 20) end = newVector(20, -40) C = A + B By default, load initializes _ ENV print(C.x, C.y) --> 30 -20 with a fixed table, called the global

NOVEMBER 2018 | VOL. 61 | NO. 11 | COMMUNICATIONS OF THE ACM 119 contributed articles

between a new vector and mt. Next, prototypes. In it, programmers repre- Figure 5 illustrates these concepts. the code defines the metamethod sent objects also by tables or userdata. First the code creates a prototype, the m t._ _a d d to implement the addition Each object can have a prototype, from table Account. The code then creates operator for vectors. The code then which it inherits methods and fields. a table mt to be used as the metat- creates two vectors, A and B, and adds The prototype of an object obj is the able for instances of Account. It then them to create a new vector C. When object stored in the __index field of adds three methods to the prototype: Lua tries to evaluate A+B, it does not the metatable of obj. One can then one for creating instances, one for know how to add tables and so checks write o bj.fo o(x), and Lua will retrieve making deposits, and one for retriev- for an __add entry in A’s metatable. the method foo from the object’s pro- ing the account’s balance. Finally, it Given that it finds that entry, Lua calls totype, through delegation. returns the prototype as the result of the function stored there—the meta- However, if we stopped here, there this module. method—passing the original oper- would be a flaw in the support for Assuming the module is in the file ands A and B as arguments. object-oriented programming in Lua. Accou nt.lua, the following lines ex- The metamethod for the indexing After finding and calling the method ercise the code operator [] offers a form of delega- in the object’s prototype, there would tion in Lua. Lua calls this metamethod, be no way for the method to access the Account = require “Account” named __inde x, whenever it tries original object, which is the intend- acc = Account:new() to retrieve the value of an absent key ed receiver. Lua solves this problem acc:deposit(1000) from a table. (For userdata, Lua calls through syntactic sugar. Lua translates print(acc:balance()) --> that metamethod for all keys.) For a “method” definition like 1000 the indexing operation, Lua allows the metamethod to be a function or a function Proto:foo (x) First, the code requires the mod- table. When __index is a table, Lua ... ule, then it creates an account; acc delegates to that table all access for an end will be an empty table with mt as its index that is absent in the original ta- metatable. De-sugared, the next line ble, as illustrated by this code fragment to a function definition: reads as acc.deposit(acc,1000). The table acc does not have a depos- Proto = {x = 0, y = 0} function Proto.foo (self, x) it field, so Lua delegates that access obj = {x = 10} ... to the table in the metatable’s __in- mt = { __index = Proto} end dex field. The result of the access is setmetatable(obj, mt) the function Account.deposit. Lua print(obj.x) --> 10 Likewise, Lua translates a “method” then calls that function, passing acc print(obj.y) --> 0 call o bj:fo o(x) to obj.foo(obj,x). as the first argument (self) and 1000 When the programmer defines a as the second argument (amount). In- In the second call to print, Lua “method”—a function using the colon side the function, Lua will again del- cannot find the key "y" in obj and so syntax—Lua adds a hidden parameter egate the access self.bal to the pro- delegates the access to Proto. In the self. When the programmer calls a totype because acc does not yet have first print, as obj has a field "x", the “method” using the colon syntax, Lua a field bal. In subsequent calls to bal- access is not delegated. provides the receiver as the argument to ance, Lua will find a field bal in the With tables, functions, and del- the self parameter. There is no need table acc and use that value. Distinct egation, we have almost all we need to add classes, objects, or methods to accounts thus have separate balances for the second tier, which is based on the language, merely syntactic sugar. but share all methods. The access to a prototype in the Figure 5. A simple prototype-based design in Lua. metatable’s __inde x is a regular access, meaning prototypes can be local Account = {bal = 0} chained. As an example, suppose the local mt = {__index = Account} programmer adds the following lines function Account:new () to the previous example local obj = {} setmetatable(obj, mt) Object = {name = “no name”} return obj end setmetatable(Account, { _ _ index = Object}) function Account:deposit (amount) self.bal = self.bal + amount When Lua evaluates acc.name, end function Account:balance () the table acc does not have a name return self.bal key, so Lua tries the access in its pro- end totype, Account. That table also does Ac- return Account not have that key, so Lua goes to count’s prototype, the table Object, where it finally finds a name field.

120 COMMUNICATIONS OF THE ACM | NOVEMBER 2018 | VOL. 61 | NO. 11 contributed articles

Figure 6. Accounts with private fields. Lua is flexible. Because method selec- whose only argument is the error ob- tion and the variable self are inde- ject. The function error also appears pendent, Lua does not need additional in the C API as a regular function de- local bal = {} setmetatable(bal, {__mode = “k”}) mechanisms to call methods from spite the fact that it never returns. other classes (such as “super”). Final- Both lua _ pcall and lua _ er- local Account = {} ly, this design is friendly to the C API. ror are reflected into Lua via the stan- local mt = {__index = Account} All it needs is basic manipulation of ta- dard library. In languages that support function Account:new () bles and functions, plus the standard try–catch, typical exception-han- local obj = {} function setmetatable. Lua pro- dling code looks like this setmetatable(obj, mt) grammers can implement prototypes bal[obj] = 0 return obj in Lua and create userdata instances in try { end C, create prototypes in C and instanc- <> es in Lua, and define prototypes with } function Account:deposit (amount) bal[self] = bal[self] + amount some methods implemented in Lua catch (errobj) { end and others in C. All these pieces work <> together seamlessly. } function Account:balance () Exception handling. Exception return bal[self] end handling in Lua is another mecha- The equivalent code in Lua is like this nism that relies on the flexibility of return Account functions. Several languages offer a local ok, errobj = try–catch construction for excep- pcall(function () tion handling; any exception in the <> The programmer can keep the bal- code inside a try clause jumps to end) ances private by storing them outside a corresponding catch clause. Lua the object table, as shown in Figure does not offer such a construction, if not ok then 6. The key difference between this ver- mainly because of the C API. <> sion and the one in Figure 5 is the use More often than not, exceptions in end of b a l[s elf] instead of self.bal to a script are handled by the host appli- denote the balance of an account. The cation. A syntactic construction like In this translation, anonymous table bal is what we call a dual table. try–catch is not easily mapped into functions with proper lexical scoping The call to setmetatable in the sec- an API with a foreign language. In- play a central role. Except for state- ond line causes this table to have weak stead, the C API packs exception-han- ments that invoke escape continua- keys, thus allowing an account to be dling functionality into the higher-or- tions (such as break and return), collected when there are no other ref- der function lua _ pcall (“protected everything else can be written inside erences to it in the program. The fact call”) we discussed when we visited the protected code as if written in the that bal is local to the module ensures the C API earlier in this article. The regular code. no code outside that module can see function pcall receives a function as The use of pcall for exception or tamper with an account’s balance, a an argument and calls that function. handling has pros and cons similar to technique that is handy whenever one If the provided function terminates those for modules. On the one hand, needs a private field in a structure. without errors, pcall returns true; the code may not look as elegant as in An evaluation of Lua’s support for otherwise, pcall catches the error other languages that support the tra- object-oriented programming is not and returns false plus an error object, ditional try. On the other hand, it has very different from the evaluation of which is any value given when the er- a clear semantics. In particular, ques- the other mechanisms we have dis- ror was raised. Regardless of how tions like “What happens with excep- cussed so far. On the one hand, object- pcall is implemented, it is exposed tions inside the catch clause?” have oriented features in Lua are not as in the C API as a conventional func- an obvious answer. Moreover, it has a easy to use as in other languages that tion. The C API also offers a function clear and easy integration with the C offer specific constructs for the task. to raise errors, called lua _ error, API; it is exposed through conventional In particular, the colon syntax can be somewhat confusing, mainly for pro- Figure 7. A simple example of a in Lua. grammers who are new to Lua but have some experience with another object- co = coroutine.create(function (x) oriented language. Lua needs that syn- print(x) --> 10 tax because of its economy of concepts x = coroutine.yield(20) print(x) --> 30 that avoids introducing the concept of return 40 method when the existing concept of end) function will suffice. print(coroutine.resume(co, 10)) --> 20 On the other hand, the semantics print(coroutine.resume(co, 30)) --> 40 of objects in Lua is simple and clear. Also, the implementation of objects in

NOVEMBER 2018 | VOL. 61 | NO. 11 | COMMUNICATIONS OF THE ACM 121 contributed articles

functions; and Lua programs can raise the coroutine again, making yield re- errors in Lua and catch them in C and turn 30, the value given to resume. The raise errors in C and catch them in Lua. coroutine then prints 30 and finishes, causing the corresponding call to re- Coroutines sume to return 40, the value returned Like associative arrays and first-class In the case by the coroutine. functions, coroutines are a well-estab- of modules, Coroutines are not as widely used in lished concept in programming. How- Lua as tables and functions. Neverthe- ever, unlike tables and first-class func- tables provide less, when required, coroutines play a tions, there are significant variations name spaces, pivotal role, due to their capacity for in how different communities imple- turning the of a program ment coroutines.2 Several of these vari- lexical scoping inside out. ations are not equivalent, in the sense An important use of coroutines in that a programmer cannot implement provides Lua is for implementing cooperative one on top of the other. encapsulation, multithreading. Games typically ex- Coroutines in Lua are like coopera- ploit this feature, because they need tive multithreading and have the fol- and first-class to be in control to remain responsive lowing distinguishing properties: functions allow at interactive rates. Each character First-class values. Lua programmers or object in a game has its own script can create coroutines anywhere, store exportation running in a separate coroutine. Each them in variables, pass them as param- of functions. script is typically a loop that, at each it- eters, and return them as results. More eration, updates the character’s state important, they can resume coroutines and then yields. A simple scheduler anywhere; resumes all live coroutines at each Suspend . They can sus- game update. pend their execution from within nest- Another use of coroutines is in tack- ed functions. Each coroutine has its ling the “who-is-the-boss” problem. A own call stack, with a semantics simi- typical issue with scripting languages lar to collaborative multithreading. is the decision whether to embed or The entire stack is preserved when the to extend. When programmers embed coroutine yields; a scripting language, the host is the Asymmetric. Symmetric coroutines boss, that is, the host program, written offer a single control-transfer opera- in the foreign language, has the main tion that transfers control from the loop of the program and calls func- running coroutine to another given tions written in the scripting language coroutine. Asymmetric coroutines, on for particular tasks. When program- the other hand, offer two control-trans- mers extend a scripting language, the fer operations, resume and yield, script is the boss; programmers then that work like a call–return pair; and write libraries for it in the foreign lan- Equivalent to one-shot continuations.2 guage, and the main loop of the pro- Despite this equivalence, coroutines gram is in the script. offer one-shot continuations in a for- Embedding and extending both mat that is more natural for a proce- have advantages and disadvantages, dural language due to its similarity to and the Lua–C API supports them multithreading. equally. However, external code can be Figure 7 illustrates the life cycle of a less forgiving. Suppose a large, mono- coroutine in Lua. The program prints lithic application contains some use- 10, 20, 30, and 40, in that order. It starts ful functionality for a particular script. by creating a coroutine co, giving an The programmer wants to write the anonymous function as its body. That script as the boss, calling functions operation returns only a to the from that external application. How- new coroutine, without running it. The ever, the application itself assumes it is program then resumes the coroutine the boss. Moreover, it may be difficult for the first time, starting the execution to break the application into individual of its body. The parameter x receives functions and offer them as a coherent the argument given to resume, and the library to the script. program prints 10. The coroutine then Coroutines offer a simpler design. yields, causing the call to resume to The programmer modifies the ap- return the value 20, the argument given plication to create a coroutine with to yield. The program then resumes the script when it starts; every time

122 COMMUNICATIONS OF THE ACM | NOVEMBER 2018 | VOL. 61 | NO. 11 contributed articles the application needs an input, it re- This is clearly true of the design of any ing of what they are doing, as most sumes that coroutine. That is the only . constructions are explicit in the code. change the programmer needs to Lua has a unique set of design goals This explicitness also allows such make in the application. The script, that prioritize simplicity, portability, deeper understanding. We trust this for its part, also looks like a regu- and embedding. The Lua core is based is a blessing, not a curse. lar program, except it yields when on three well-known, proven con- it needs to send a command to the cepts—associative arrays, first-class References 1. Cazzola, W. and Olivares, D.M. Gradually learning application. The control flow of the functions, and coroutines—all imple- programming supported by a growable programming language. IEEE Transactions on Emerging Topics in resulting program progresses as fol- mented with no artificial restrictions. Computing 4, 3 (July 2016), 404–415. lows: The application starts, creates On top of these components, Lua fol- 2. de Moura, A.L and Ierusalimschy, . Revisiting coroutines. ACM Transactions on Programming the coroutine, does its own initializa- lows the motto “mechanisms instead Languages and Systems 31, 2 (Feb. 2009), 6.1–6.31. tion, and then waits for input by re- of policies,” meaning Lua’s design 3. Gamasutra. Game Developer magazine’s 2011 Front Line Award, Jan. 13, 2012; https://www.gamasutra. suming the coroutine. The coroutine aims to offer basic mechanisms to al- com/view/news/129084/ then starts running, does its own ini- low programmers to implement more 4. Hayes, B. Ephemerons: A new finalization mechanism. In Proceedings of the 12th ACM SIGPLAN Conference tialization, and performs its duties complex features. For instance, in the on Object-Oriented Programming, Systems, until it needs some service from the case of modules, tables provide name Languages, and Applications (Atlanta, GA, Oct. 5–9). ACM, New York, 1997, 176–183. application. At this point, the script spaces, lexical scoping provides encap- 5. Ierusalimschy, R. Programming with multiple yields with a request, the call to re- sulation, and first-class functions allow paradigms in Lua. In Proceedings of the 18th International Workshop on Functional and (Constraint) sume made by the application re- exportation of functions. On top of that, Logic Programming, LNCS, Volume 5979. S. Escobar, turns, and the application services Lua adds only the function require to Ed. (Brasilia, Brazil, June 28). Springer, Heidelberg, Germany, 2009, 5–13. the given request. The application search for and load modules. 6. Ierusalimschy, R., de Figueiredo, L.H., and Celes, W. then waits for the next request by re- Modularity in language design is Lua—An extensible extension language. : Practice and Experience 26, 6 (June 1996), 635–652. 11 suming the script again. nothing new. For instance, it can 7. Ierusalimschy, R., de Figueiredo, L.H., and Celes, W. be used to clarify the construction The evolution of Lua. In Proceedings of the Third ACM Presentation of coroutines in SIGPLAN Conference on History of Programming the C API is clearly more challeng- of a large application.1 However, Lua Languages (San Diego, CA, June 9–10). ACM Press, New York, 2007, 2.1–2.26. ing than presentation of functions uses modularity to keep its size small, 8. Ierusalimschy, R., de Figueiredo, L.H., and Celes, and tables. C code can create and breaking down complex constructions W. Passing a language through the eye of a needle. Commun. ACM 54, 7 (July 2011), 38–43. resume coroutines without restric- into existing mechanisms. 9. International Organization for Standardization. tions. In particular, resuming works The motto “mechanisms instead of ISO 2000. International Standard: Programming Languages, C. ISO/IEC9899: 1999(E). like a regular function call: It (re) policies” also makes for a flexible lan- 10. Jones, R., Hosking, A., and Moss, E. The Garbage activates the given coroutine when guage, sometimes too flexible. For in- Collection Handbook. CRC Press, Boca Raton, FL, 2011. 11. Kats, L. and Visser, E. The Spoofax Language called and returns when the corou- stance, the do-it-yourself approach to Workbench: Rules for declarative specification of tine yields or ends. However, yield- classes and objects leads to prolifera- languages and IDEs. In Proceedings of the ACM International Conference on Object Oriented ing also poses a problem. Once a C tion of different, often incompatible, Programming Systems Languages and Applications function yields, there is no way to systems, but is handy when a program- (Reno/Tahoe, NV, Oct. 17–21). ACM Press, New York, 2010, 444–463. later return the control to that point mer needs to adapt Lua to the class 12. The Python Software Foundation. The Python in the function. The API offers two model of the host program. Language Reference, 3.5 Edition. The Python Software Foundation, 2015. ways to circumvent this restriction: Tables, functions, and coroutines as 13. Sestoft, P. Programming Language Concepts, Second Edition. Springer, Cham, Switzerland, 2017. The first is to yield in a tail position: used in Lua have shown great flexibility 14. Wikipedia. List of applications using Lua; https:// When the coroutine resumes, it goes over the years. Despite the language’s en.wikipedia.org/w/index.php?title=List_of_ straight to the calling Lua function. continuing evolution, there has been applications_using_Lua&oldid=795421653 The second is to provide a continua- little demand from programmers to Roberto Ierusalimschy ([email protected]) is an tion function when yielding. In this change the basic mechanisms. associate professor of science at PUC-Rio, the way, when the coroutine resumes, The lack of built-in complex con- Pontifical Catholic University of Rio de Janeiro, Brazil. the control goes to the continuation structions and minimalist standard Luiz Henrique de Figueiredo ([email protected]) is a researcher at IMPA, the Institute for Pure and Applied function, which can finish the task libraries (for portability and small Mathematics in Rio de Janeiro, Brazil. of the original function. size) make Lua a language that is not Waldemar Celes ([email protected]) is an associate We can see again in the API the ad- as good as other scripting languages professor of computer science at PUC-Rio, the Pontifical Catholic University of Rio de Janeiro, Brazil. vantages of asymmetric coroutines for for writing “quick-and-dirty” pro- a language like Lua. With symmetric grams. Many programs in Lua need coroutines, all transfers would have an initial phase for programmers to Copyright held by the authors. the problems that asymmetric corou- set up the language, as a minimal in- Publication rights licensed to ACM. $15.00 tines have only when yielding. In our frastructure for object-oriented pro- experience, resumes from C are much gramming. More often than not, Lua more common than yields. is embedded in a host application. Embedding demands planning and Conclusion the set-up of the language is typically Watch the authors discuss Every design involves balancing con- integrated with its embedding. Lua’s this work in the exclusive Communications video. flicting goals. To address the conflicts, economy of concepts demands from https://cacm.acm.org/videos/ designers need to prioritize their goals. programmers a deeper understand- a-look-at-the-design-of-lua

NOVEMBER 2018 | VOL. 61 | NO. 11 | COMMUNICATIONS OF THE ACM 123