A Look at the Design Of
Total Page:16
File Type:pdf, Size:1020Kb
contributed articles 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- 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 coroutines LUA 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- itself to several other paradigms, including object- tures, garbage collection, and an eval- 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 ˽ 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 Linux 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 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 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 free. For instance, when a use tables not only for all kinds of data programmer 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.