Cacm 2018
Cacm 2018
DOI:10.1145/ 3186277
build a new abstraction. Encapsu-
Simplicity, small size, portability, lation in the C 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 programmers 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-
A Look at
sic mechanisms provided by the C lan-
guage, policy adds several rules (such
as “all global functions should have a
prototype in a header file” and “header
the Design
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.
of Lua
Accordingly, in the design of Lua,
we have replaced addition of many
different features by creating instead
only a few mechanisms that allow
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 coroutines
L UA IS A scripting language 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-
tactic 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 Wikipedia.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-
tures, garbage collection, and an eval-
itself to several other paradigms, including object- like functionality. Consider Lua’s par-
oriented programming, functional 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
JSON. Data description was indeed one of our main ˽˽ What sets Lua apart from other scripting
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
IMAGE BY BUG F ISH
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 basic tasks. The stand- we first briefly introduce the interface
dress several different needs, instead alone Lua interpreter is a tiny applica- between Lua and its host language.
of myriad specific language constructs, tion written on top of the library.
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 global variable 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 thread, 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 <stdio.h>
#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
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 source code, 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 form 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
function M.norm (v)
id = id + 1 return math.sqrt(v.x^2 + v.y^2)
code. The variable M is local to that
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 function add (u, v)
the single argument to a function is a
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- exception handling. 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 local variable 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 static variable in Concretely, the language sees math as has a clear semantics that requires no
C or a class variable in Java. 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.
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 _ ENV.norm. 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 compiler. 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 rewrite 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.
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
mt.__add 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 obj.foo(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. Account.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 __index, 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 obj:foo(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 __index 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
return Account
not have that key, so Lua goes to Ac-
count’s prototype, the table Object,
where it finally finds a name field.
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)
bal[obj] = 0
grammers can implement prototypes
return obj in Lua and create userdata instances in try {
end C, create prototypes in C and instanc- <<protected code>>
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 <<exception handling>>
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 <<protected code>>
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. <<exception handling>>
sion and the one in Figure 5 is the use More often than not, exceptions in end
of bal[self] 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 coroutine in Lua.
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
Like associative arrays and first-class In the case sume to return 40, the value returned
by the coroutine.
functions, coroutines are a well-estab-
lished concept in programming. How-
of modules, Coroutines are not as widely used in
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
in how different communities imple-
name spaces, pivotal role, due to their capacity for
turning the control flow of a program
ment coroutines.2 Several of these vari- lexical scoping inside out.
ations are not equivalent, in the sense
that a programmer cannot implement
provides An important use of coroutines in
Lua is for implementing cooperative
one on top of the other. encapsulation, multithreading. Games typically ex-
Coroutines in Lua are like coopera-
tive multithreading and have the fol- and first-class ploit this feature, because they need
to be in control to remain responsive
lowing distinguishing properties: functions allow at interactive rates. Each character
First-class values. Lua programmers
can create coroutines anywhere, store exportation or object in a game has its own script
running in a separate coroutine. Each
them in variables, pass them as param-
eters, and return them as results. More
of functions. script is typically a loop that, at each it-
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 execution. 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 handle 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
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 programming language. 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
resulting program progresses as fol- language. IEEE Transactions on Emerging Topics in
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, R. 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. Software:
Practice and Experience 26, 6 (June 1996), 635–652.
suming the script again. nothing new.11 For instance, it can 7. Ierusalimschy, R., de Figueiredo, L.H., and Celes, W.
Presentation of coroutines in be used to clarify the construction The evolution of Lua. In Proceedings of the Third ACM
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
The first is to yield in a tail position: used in Lua have shown great flexibility Edition. Springer, Cham, Switzerland, 2017.
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_
applications_using_Lua&oldid=795421653
straight to the calling Lua function. continuing evolution, there has been
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 computer 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