Retired Lua Faq

lua-users home
wiki

[A few of the following may still be salvageable]

Programming in Lua

How do I declare variables?

You don't: Lua does not have or need variable declarations.

But why do you need to declare variables?

Some people want to declare variables to protect themselves against typing mistakes. For example, the code

color="red"

print(colour)

will print nil because color has been mistyped in line 2 and colour has not been defined.

To safeguard against these mistakes, and also to spot undefined variables, you can use the getglobal tag method:

function safe_getglobal(x)

  local v=rawgetglobal(x)

  if v then return v else error("undefined global variable "..x) end

end



settagmethod(tag(nil),"getglobal",safe_getglobal)

With this code in place, any attempt to use an undefined variable (which would have the value nil) will produce an error message.

How do I do typing in Lua?

Lua is a dynamically typed language. This means that variables do not have type, only values do. Since Lua provides access to the type of values (via the type function), you can write your own functions for dynamic typing. Here is one possible scheme.

To check simple types, just use type. The interesting case is checking tables, because we must check that all fields are present and correctly filled, according to pre-defined "templates". So, we need a way to describe the "type" of tables. As mentioned above, a simple type is described by its name, as reported by the type function. Tables are described by "type templates", which are tables that map each field to its required type. Here are some examples useful for user interface toolkits:

TNumber="number"

TPoint={x=TNumber, y=TNumber}

TColor={red=TNumber, blue=TNumber, green=TNumber}

TRectangle={topleft=TPoint, botright=TPoint}

TWindow={title="string", bounds=TRectangle, color=TColor}

Given such descriptions, the following function checks whether a value has a given type:

function checkType(d, t)

  if type(t) == "string" then

    -- t is the name of a type

    return (type(d) == t)

  else

    -- t is a table, so d must also be a table

    if type(d) ~= "table" then

      return nil

    else

      -- d is also a table; check its fields

      local i,v = next(t,nil)

      while i do

        if not checkType(d[i],v) then

          return nil

        end

        i,v = next(t,i)

      end

    end

  end

  return 1

end

How do I create read-only variables?

In large projects, and also in libraries, it is sometimes important to protect some variables so that they cannot be redefined. This is specially useful when several libraries are loaded and you want to make sure they don't redefine each other's functions by accident.

You can protect functions in Lua by using the setglobal tag method:

function protect(x)

  error("cannot redefine "..x)

end



settagmethod(tag(protect),"setglobal",protect)

This code should be run after all libraries have been loaded.

With this code in place, any attempt to redefine functions will produce an error message. You can still redefine functions, but you have to do it explicitly:

rawsetglobal("print",nil)

function print (x) ... end

To extend this scheme to other kinds of values, you need to wrap values with tables, and use both setglobal and getglobal tag methods:

RO=newtag()				-- tag for read-only values



function ROvalue(value)			-- make a read-only value

  local t={value=value}

  settag(t,RO)

  return t



end



function ROsetglobal(x)			-- protects assignment

  error(x.." is read-only")

end



function ROgetglobal(x,value)		-- get the actual value

  return value.value

end



settagmethod(RO,"getglobal",ROgetglobal)

settagmethod(RO,"setglobal",ROsetglobal)



tolerance=ROvalue(0.12)			-- make some read-only variables

color=ROvalue("red")

myprint=ROvalue(print)

This scheme only affects variables created with ROvalue, because only those have the RO tag.

How are block comments done in Lua?

Lua 5.0 now has a block comment syntax:

--Double-dashes begin a single-line comment



--[[Double-dashes immediately followed by double left square bracket

    Begin a multi-line comment

    That continues until the __matching__ double right square bracket,

    so you can do [[this]] too. ]]

The following information about block comments applies for versions prior to 5.0.

Lua doesn't have a special syntax for block comments. One solution is to enclose the comment in a string:

comment = [[

    this is my

    multi-line comment

]]

A variant of this solution, which is convenient for temporarily disabling a block of code, is the following:

comment = [[

    disabled code

--]]

You can enable the code simply by adding -- to the assigment:

--comment = [[

    enabled code

--]]

If the block is big, you may want to avoid letting it float in memory until the garbage collector removes it. You can then write:

local comment = [[

    disabled code

--]] ; comment = nil

Luiz Henrique de Figueiredo suggested also:

do local C=[[

--]] end

"C goes immediately out of scope. The parser could exploit this (but doesn't). There's also:"

local C= 1 or [[

<syntaxly correct code to comment out>

--]]

"The code generator could exploit this (but doesn't)."

Another solution is to use an editor macro to prefix selected lines with "-- "; or with "--~ " for example, so the commented block stand out of surrounding regular comments.

For commenting out a block of code, it's possible to use if nil then ... end. (See the next question.)

How do I clone objects?

In Lua, tables are manipulated by reference. So, if the value of x is a table, then the assignment y=x does not duplicate the table: x and y contain the same table. (In other words, the values of x and y are references to the same table.)

If you really want to copy a table, you can use the built-in function next, as in the code below:

function clone(t)            -- return a copy of the table t

  local new = {}             -- create a new table

  local i, v = next(t, nil)  -- i is an index of t, v = t[i]

  while i do

    new[i] = v

    i, v = next(t, i)        -- get next index

  end

  return new

end

If you want a deep copy , add if type(v)=="table" then v=clone(v) end before new[i] = v.

How do I implement sets using tables?

The best way to implement a set in Lua is to store its elements as keys in a table. An element is present in a set when the corresponding value in the table is not nil.

Here are some code snippets for sets:

s={}			-- create an empty set

s[x]=1			-- insert element x into set s

s[x]=nil		-- remove element x from set s

x_is_present=s[x]	-- does s contain x?

Bags are similar to sets, except that elements may appear more than once. Bags can be implemented similarly to sets, but using the value associated to an element as its counter. Here is a code snippet for bags:

-- insert element x into bag s

if s[x] then s[x] = s[x]+1 else s[x] = 1 end



-- remove element x from set s

if s[x] then

  s[x] = s[x]-1

  if s[x] == 0 then s[x] = nil end

end

How do I convert a number to char?

As of Lua 5.0, use string.char(n) or even string.format("%c", n). Prior to Lua 5.0, use strchar(n) or format("%c",n).

How do I read words, numbers, quoted strings, etc?

[needs updating!]

The pattern matching capabilities of read are powerful, but writing patterns is not for everyone. Here are some useful patterns:


Word (sequence of letters and digits)

        {{"%w%w*"}}

Word (sequence of non-white space characters)

        {{"%S%S*"}}

Integer

        {{"[+-]?%d%d*"}}

Real

        {{"[+-]?%d%d*[.]%d%d*"}}

Double quoted string

        {{'"[^"]*"'}}

Single quoted string

        {{"'[^']*'"}}

If you want to skip whitespace before reading an item, just prepend "{%s*}" to your pattern. For instance, "{%s*}%S%S*" skips whitespace and then reads the next word.

Version 3.2 made this even simpler: you can use "*w" to read a word and "*n" to read a number. See the reference manual for a complete list of predefined patterns.

How do I write a self-reproducing program in Lua?

Writing a self-reproducing program in any language is fun but not always easy because you have to be careful with quotes. In Lua it is easy because there are alternative quotes:

y = [[ print("y = [[" .. y .. "]]\ndostring(y)") ]]

dostring(y)

VersionNotice: above is Lua 4.0.

For self-reproducing programs in other languages, see the Quine page [1]. Read also a good explanation of how self-reproducing programs work [2].

How do I save/restore the global environment?

[needs updating!]

Try this code:

function save()

  local g={}

  foreachvar(function (n,v) %g[n]=v end)

  return g

end



function restore(g)

  foreach(g,setglobal)

end

Since version 3.1, you can do these same, and much more, in C, using lua_open, lua_close, and lua_setstate.

Interfacing C with Lua

How do I write a C function to be called from Lua?

[needs updating!]

You must follow a simple protocol: Get any parameters from Lua with lua_getparam, make sure they are of the correct type with the appropriate lua_is... function, convert them with the appropriate lua_get... function, do something with the converted values, and push the results back to Lua with the appropriate lua_push... function.

Let's see a practical example and export the getenv function to Lua. For more examples, see the code that implements the standard library.

The getenv function in C takes a string and returns another string. Its prototype is


char* getenv(char*);

So, the appropriate functions to call are lua_isstring, lua_getstring and lua_pushstring:


void wrap_getenv(void) {

 lua_Object o=lua_getparam(1);

 if (lua_isstring(o))

  lua_pushstring(getenv(lua_getstring(o)));

 else

  lua_error("string expected in argument #1 to getenv");

}

Since version 3.0, Lua includes auxiliary functions that simplify writing wrappers. With these functions, we can write wrap_getenv as:


void wrap_getenv(void) {

 lua_pushstring(getenv(luaL_check_string(1)));

}

After writing the wrapper, you must make it visible to Lua by calling lua_register("getenv",wrap_getenv). In fact, this is almost exactly what the standard library does.

How can I use my favorite C library with Lua?

Just write a wrapper for each function in your library, as explained above.

Several solutions are provided for automating this process. See "Code wrappers" on LuaAddons.

What is "stack size overflow"?

VersionNotice: this is Pre-Lua5.

Except for trivial cases, such as an infinite recursion, you get this message when you call Lua from C in a loop because arguments and return values accumulate in Lua's stack. For example, this code will produce "stack size overflow":


 for (i=0;;i++) {

  lua_pushnumber(i);

  lua_call("print");

 }

The solution is to enclose the code that talks to Lua with calls to lua_beginblock and lua_endblock:


 for (i=0;;i++) {

  lua_beginblock();

  lua_pushnumber(i);

  lua_call("print");

  lua_endblock();

 }

To quote from the reference manual: The use of explicit nested blocks is strongly encouraged.


RecentChanges · preferences
edit · history
Last edited June 3, 2009 12:28 pm GMT (diff)