This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 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
like 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.
The dofile
function is actually an auxiliary function;
loadfile
does the hard work.
Like dofile
, loadfile
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.
Moreover, unlike dofile
,
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
assert
to raise an error if loadfile
fails.
For simple tasks,
dofile
is handy, as it does the whole job in one call.
However, 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 dofile
,
because the program compiles the file only once.
The loadstring
function is similar to loadfile
,
except that it reads its chunk from a string,
not from a file.
For instance, after the code
f = loadstring("i = i + 1")
f
will be a function that,
when invoked, executes i = i + 1
:
i = 0 f(); print(i) --> 1 f(); print(i) --> 2The
loadstring
function 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
Both loadstring
and 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
loadfile
(or 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 foo.lua
like this:
-- file `foo.lua' function foo (x) print(x) endWe then run the command
f = loadfile("foo.lua")After this command,
foo
is 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 dostring
(i.e., to load and run a chunk) you may call the result from
loadstring
directly:
loadstring(s)()However, if there is any syntax error,
loadstring
will return nil
and the final error message will be an
"attempt to call a nil value"
.
For clearer error messages, use assert
:
assert(loadstring(s))()
Usually, it does not make sense to use loadstring
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
loadstring
involves a new compilation.
However, the two codes are not completely equivalent,
because loadstring
does 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
g
function manipulates the local i
, as expected,
but f
manipulates a global i
,
because loadstring
always 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.
Note that 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 loadstring
.
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. |