Lua in a Nutshell: A Quick Tutorial for Lua

I'm reading source code written with Torch these days. Torch is a well-known deep learning framework written by Lua.

So I summarize the grammar of it and provide a quick tutorial here.

Run

As we know, Lua is a C-like language. Therefore, it is case-sensitive.

The following code outputs "Hello World" with Lua. Note that the semicolon at the end of a line is optional, like JavaScript.

<br />
print('Hello World')<br />

You can use the interrupter of Lua in the command line:

<br />
➜  ~ lua<br />
Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio<br />
&gt; print('Hello World')<br />
Hello World<br />
&gt;<br />

Also, you can run a Lua script with a file in the command line:

lua hello.lua

Grammar

Comment

<br />
-- This is a line comment</p>
<p>--[[<br />
  This is a block<br />
  comment<br />
--]]<br />

Variables

The numbers in Lua are all doubles with 64 bits. And you can use following expressions:

<br />
num = 1024<br />
num = 1.0<br />
num = 3.1416<br />
num = 314.16e-2<br />
num = 0.31416E1<br />
num = 0xff<br />

You can use both double and single quotes for strings. For example:

<br />
str = 'Hello World'<br />
str = &quot;Hello World&quot;<br />

Also, escape characters still exist in Lua:

<br />
ch = '\a'<br />
ch = '\t\n'<br />

The following four lines define the same string:

<br />
a = 'abc\n123&quot;'<br />
a = &quot;abc\n123\&quot;&quot;<br />
a = '\97bc\10&#92;&#48;4923&quot;'<br />
a = [[abc<br />
123&quot;]]<br />

The NULL in C is represented with nil in Lua. When you try to get values from undefined variables, it will return nil:

<br />
v = UndefinedVariable<br />

false and nil represent false for a boolean value in Lua. Other values including 0 represent true for a boolean value.

By the way, all variables are global variables unless declared explicitly:

<br />
globalVar = 50<br />
local localVar = 'local variable'<br />

Control Statements

If-else Branches

<br />
if age == 40 and sex == 'Male' then<br />
    print('40-year-old man is a flower (:')<br />
elseif age &gt; 60 and sex ~= 'Female' then<br />
    print('The elder')<br />
elseif age &lt; 20 then<br />
    print('Too young, too naive!')<br />
else<br />
    local age = io.read()<br />
    print('Your age is '..age)<br />
end<br />

Besides if-else statements, we also present some other grammar of Lua:

  • The operator == tests for equality; the operator ~= is the negation of equality
  • The string concatenation operator in Lua is denoted by two dots ('..').
  • You can get stdin and stdout with read and write functions in io library

While Loop

<br />
sum = 0<br />
num = 1<br />
while num &lt;= 100 do<br />
    sum = sum + num<br />
    num = num + 1<br />
end<br />
print('sum = ', sum)<br />

For Loop

The following code calculates the sum of integers from 1 to 100:

<br />
sum = 0<br />
for i = 1, 100 do<br />
    sum = sum + i<br />
end<br />

The following code calculates the sum of odd numbers from 1 to 100:

<br />
sum = 0<br />
for i = 1, 100, 2 do<br />
    sum = sum + i<br />
end<br />

The following code calculates the sum of even numbers from 1 to 100:

<br />
sum = 0<br />
for i = 100, 1, -2 do<br />
    sum = sum + i<br />
end<br />

Repeat Loop

<br />
sum = 2<br />
repeat<br />
   sum = sum ^ 2 -- Equivalent to sum = sum * sum<br />
   print(sum)<br />
until sum &gt;1000<br />

Functions

Recursion

<br />
function fib(n)<br />
  if n &lt; 2 then return 1 end<br />
  return fib(n - 2) + fib(n - 1)<br />
end<br />

Closure

<br />
function newCounter()<br />
    local i = 0<br />
    return function()     -- anonymous function<br />
        i = i + 1<br />
        return i<br />
    end<br />
end</p>
<p>c1 = newCounter()<br />
print(c1())  --&gt; 1<br />
print(c1())  --&gt; 2<br />

And here's another example:

<br />
function myPower(x)<br />
    return function(y) return y^x end<br />
end</p>
<p>power2 = myPower(2)<br />
power3 = myPower(3)<br />
print(power2(4)) --&gt; 4^2<br />
print(power3(5)) --&gt; 5^3<br />

The Return Values of Functions

Like Python, you can assign multiple values in one statement, for example:

<br />
a, b, c = 1, 2, 3, 4<br />

Please note that the fourth value will be ignored since there're only three variables.

The functions in Lua can return multiple values:

<br />
function f(x)<br />
    print(x)<br />
    return 1, 2, 3<br />
end</p>
<p>a, b, c, d = f()<br />

The output in line 2 will be nil because x is not assigned a value when f() is invoked. Also, the variable d in line 6 will also be nil.

Table

Actually, Table is a key-value data structure, as known as Map in other programming languages. We can define a new Table as following:

<br />
hzxie = {<br />
    name = &quot;Haozhe Xie&quot;,<br />
    email = &quot;cshzxie@gmail.com&quot;,<br />
    homepage = &quot;https://haozhexie.com&quot;<br />
}<br />

And you can get or set values as follows:

<br />
print(hzxie.name)<br />
hzxie.name = nil<br />

You can also define a Table in following ways:

<br />
anotherTable = {<br />
    [20] = 10,<br />
    ['name'] = &quot;Haozhe Xie&quot;<br />
}<br />

And then, you can access values in anotherTable in a more map-like way:

<br />
local v20 = anotherTable[20];<br />
print(anotherTable['name'])<br />

Now, let's look at arrays.

<br />
arr = {10, 20, 30, 40, 50}<br />

It is equivalent to:

<br />
arr = {[1] = 10, [2] = 20, [3] = 30, [4] = 40, [5] = 50}<br />

Please note that the index starts from 1 instead of 0 in Lua.

In addition, you can put different types of variables to an array:

<br />
arr = {&quot;Say Hello&quot;, 2, function() return &quot;to a function.&quot; end}<br />

And you can invoke the function in the array with arr[3]().

You can traverse values in an array as follows:

<br />
for i=1, #arr do<br />
    print(arr[i])<br />
end<br />

where the #arr represents the length of the array.

As mentioned above, if you declare a variable without local, it will be a global variable. All global variables will be stored in a Table named _G. Suppose there is a global variable named globalVar, you can access this variable in following ways:

<br />
_G.globalVar<br />
_G['globalVar']<br />

You can traverse values in a table as follows:

<br />
for k, v in pairs(t) do<br />
    print(k, v)<br />
end<br />

Meta Tables and Meta Methods

Metatables and Metamethods are one of the most important grammars in Lua. Metatables allow us to change the behavior of a table. For instance, using metatables, we can define how Lua computes the expression a + b, where a and b are tables. Whenever Lua tries to add two tables, it checks whether either of them has a metatable and whether that metatable has an __add field. If Lua finds this field, it calls the corresponding value (the so-called metamethod, which should be a function) to compute the sum.

For example, we have two fractions with values of 2/3 and 4/7:

<br />
fraction1 = {numerator=2, denominator=3}<br />
fraction2 = {numerator=4, denominator=7}<br />

And we are about to add them together. However, we cannot add them together with the operator +. But we can make it with metamethods:

<br />
fractionOperations={}<br />
function fractionOperations.__add(f1, f2)<br />
    ret = {}<br />
    ret.numerator = f1.numerator * f2.denominator + f2.numerator * f1.denominator<br />
    ret.denominator = f1.denominator * f2.denominator<br />
    return ret<br />
end</p>
<p>setmetatable(fraction1, fractionOperations)<br />
setmetatable(fraction2, fractionOperations)<br />

And now, you can add them together as follows:

<br />
frac = fraction1 + fraction2<br />

The __add metamethod corresponds to the operator +. Other metamethods are listed as following:

<br />
__add(a, b)               -&gt; Corresponds to a + b<br />
__sub(a, b)               -&gt; Corresponds to a - b<br />
__mul(a, b)               -&gt; Corresponds to a * b<br />
__div(a, b)               -&gt; Corresponds to a / b<br />
__mod(a, b)               -&gt; Corresponds to a % b<br />
__pow(a, b)               -&gt; Corresponds to a ^ b<br />
__unm(a)                  -&gt; Corresponds to -a<br />
__concat(a, b)            -&gt; Corresponds to a .. b<br />
__len(a)                  -&gt; Corresponds to #a<br />
__eq(a, b)                -&gt; Corresponds to a == b<br />
__lt(a, b)                -&gt; Corresponds to a &lt; b<br />
__le(a, b)                -&gt; Corresponds to a &lt;= b<br />
__index(a, b)             -&gt; Corresponds to a.b<br />
__newindex(a, b, c)       -&gt; Corresponds to a.b = c<br />
__call(a, ...)            -&gt; Corresponds to a(...)<br />

Object-oriented Programming

There is a function named __index in metamethods. If you want to make b as a property of a, you can do as following:

<br />
setmetatable(a, {__index = b})<br />

And here's another example:

<br />
WindowPrototype = {x=0, y=0, width=100, height=100}<br />
MyWindow = {title=&quot;Hello&quot;}<br />
setmetatable(MyWindow, {__index = WindowPrototype})<br />

When indexing a key in a table, Lua firstly finds it in the table. If the key not exists, it will invoke the __index() function.

Now, let's talk about object-oriented programming:

<br />
Person={}</p>
<p>function Person:new(p)<br />
    local obj = p<br />
    if (obj == nil) then<br />
        obj = {name = &quot;Haozhe Xie&quot;, handsome = true}<br />
    end<br />
    self.__index = self<br />
    return setmetatable(obj, self)<br />
end</p>
<p>function Person:toString()<br />
    return self.name ..&quot; : &quot;.. (self.handsome and &quot;handsome&quot; or &quot;ugly&quot;)<br />
end<br />

Now we can create objects of Person class:

<br />
me = Person:new()<br />
print(me:toString())</p>
<p>someone = Person:new{name=&quot;Someone&quot;, handsome=false}<br />
print(someone:toString())<br />

The following code gives an example of inherit in Lua:

<br />
Student = Person:new()</p>
<p>function Student:new()<br />
    newObj = {stuId = &quot;15S103172&quot;}<br />
    self.__index = self<br />
    return setmetatable(newObj, self)<br />
end</p>
<p>function Student:toString()<br />
    return &quot;Student : &quot;.. self.stuId..&quot; : &quot; .. self.name<br />
end<br />

Modules

We can include other lua scripts with the function require(). Once a script is loaded, it will be executed automatically.

For example, we have a Lua script named hello.lua with following content:

<br />
print(&quot;Hello, World!&quot;)<br />

Once we use require("hello"), you will get "Hello, World" on your screen. Please note that the script will be executed ONLY once no matter how many times you require this script.

If you want the script to be executed every time, you can use dofile function instead. And if you want to load a Lua script without being executed, you can use loadfile function.

You can use it as follows:

<br />
local hello = loadfile(&quot;hello&quot;)<br />
-- Do something...<br />
hello()<br />

Here's a more standard example:

File Name: MyModel.lua

<br />
local MyModel = {}</p>
<p>local function getname()<br />
    return &quot;Haozhe Xie&quot;<br />
end</p>
<p>function MyModel.greeting()<br />
    print(&quot;Hello, My name is &quot;..getname())<br />
end</p>
<p>return MyModel<br />

And we can load the model above as follows:

<br />
local myModel = require(&quot;MyModel&quot;)<br />
myModel.greeting()<br />

Actually, the require() function works as follows:

<br />
local myModel = (function ()<br />
  -- The content of MyModel.lua --<br />
end)()<br />

References

  • https://www.lua.org/pil/
  • https://coolshell.cn/articles/10739.html
Contact Us
  • Room 614, Zonghe Building, Harbin Institute of Technology
  • cshzxie [at] gmail.com