This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The third edition targets Lua 5.2 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.
|Programming in Lua|
|Part I. The Language Chapter 8. Compilation, Execution, and Errors|
Although we refer to Lua as an interpreted language,
Lua always precompiles source code to an
intermediate form before running it.
(This is not a big deal:
Most interpreted languages do the same.)
The presence of a compilation phase may sound out of place in
an interpreted language like Lua.
However, the distinguishing feature of interpreted languages
is not that they are not compiled,
but that any compiler is part of the language runtime
and that, therefore, it is possible (and easy) to execute
code generated on the fly.
We may say that the presence of a function
dofile is what allows Lua
to be called an interpreted language.
Previously, we introduced
dofile as a kind of primitive
operation to run chunks of Lua code.
dofile function is actually an auxiliary function;
loadfile does the hard work.
also loads a Lua chunk from a file,
but it does not run the chunk.
Instead, it only compiles the chunk
and returns the compiled chunk as a function.
loadfile does not raise errors,
but instead returns error codes,
so that we can handle the error.
We could define
dofile as follows:
function dofile (filename) local f = assert(loadfile(filename)) return f() endNote the use of
assertto raise an error if
For simple tasks,
dofile is handy, as it does the whole job in one call.
loadfile is more flexible.
In case of errors,
loadfile returns nil plus the error message,
which allows us to handle the error in customized ways.
Moreover, if we need to run a file several times,
we can call
loadfile once and
call its result several times.
This is much cheaper than several calls to
because the program compiles the file only once.
loadstring function is similar to
except that it reads its chunk from a string,
not from a file.
For instance, after the code
f = loadstring("i = i + 1")
fwill be a function that, when invoked, executes
i = i + 1:
i = 0 f(); print(i) --> 1 f(); print(i) --> 2The
loadstringfunction is powerful; it must be used with care. It is also an expensive function (when compared to its alternatives) and may result in incomprehensible code. Before you use it, make sure that there is no simpler way to solve the problem at hand.
Lua treats any independent chunk
as the body of an anonymous function.
For instance, for the chunk
"a = 1",
loadstring returns the equivalent of
function () a = 1 endLike any other function, chunks can declare local variables and return values:
f = loadstring("local a = 10; return a + 20") print(f()) --> 30
loadfile never raise errors.
In case of any kind of error,
both functions return nil plus an error message:
print(loadstring("i i")) --> nil [string "i i"]:1: `=' expected near `i'Moreover, both functions never have any kind of side effect. They only compile the chunk to an internal representation and return the result, as an anonymous function. A common mistake is to assume that
loadstring) defines functions. In Lua, function definitions are assignments; as such, they are made at runtime, not at compile time. For instance, suppose we have a file
-- file `foo.lua' function foo (x) print(x) endWe then run the command
f = loadfile("foo.lua")After this command,
foois compiled, but it is not defined yet. To define it, you must run the chunk:
f() -- defines `foo' foo("ok") --> ok
If you want to do a quick-and-dirty
(i.e., to load and run a chunk) you may call the result from
loadstring(s)()However, if there is any syntax error,
loadstringwill return nil and the final error message will be an
"attempt to call a nil value". For clearer error messages, use
Usually, it does not make sense to use
on a literal string.
For instance, the code
f = loadstring("i = i + 1")is roughly equivalent to
f = function () i = i + 1 endbut the second code is much faster, because it is compiled only once, when the chunk is compiled. In the first code, each call to
loadstringinvolves a new compilation. However, the two codes are not completely equivalent, because
loadstringdoes not compile with lexical scoping. To see the difference, let us change the previous examples a little:
local i = 0 f = loadstring("i = i + 1") g = function () i = i + 1 endThe
gfunction manipulates the local
i, as expected, but
fmanipulates a global
loadstringalways compiles its strings in a global environment.
The most typical use of
loadstring is to run external code,
that is, pieces of code that come from outside your program.
For instance, you may want to plot a function defined by the user;
the user enters the function code
and then you use
loadstring to evaluate it.
loadstring expects a chunk, that is, statements.
If you want to evaluate an expression,
you must prefix it with return,
so that you get a statement that returns the value of the given expression.
See the example:
print "enter your expression:" local l = io.read() local func = assert(loadstring("return " .. l)) print("the value of your expression is " .. func())
The function returned by
loadstring is a regular function,
so you can call it several times:
print "enter function to be plotted (with variable `x'):" local l = io.read() local f = assert(loadstring("return " .. l)) for i=1,20 do x = i -- global `x' (to be visible from the chunk) print(string.rep("*", f())) end
In a production-quality program that needs to run external code,
you should handle any errors reported by
Moreover, if the code cannot be trusted,
you may want to run the new chunk in a protected environment,
to avoid unpleasant side effects when running the code.
|Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved.|