Basic Programming Techniques

Corona uses a scripting language called Lua as its programming environment.

Lua is a programming language known for its speed and ease of use by non-programmers, and is commonly used in the game-development industry. The syntax is different from JavaScript, but both share many common semantics.

Conventions

Names (also called identifiers) in Lua can be any string of letters, digits, and underscores, not beginning with a digit. This coincides with the definition of names in most languages. (The definition of letter depends on the current locale: any character considered alphabetic by the current locale can be used in an identifier.) Identifiers are used to name variables and table fields.

The following keywords are reserved and cannot be used as names:

     and       break     do        else      elseif
     end       false     for       function  if
     in        local     nil       not       or
     repeat    return    then      true      until     while

Lua is a case-sensitive language: and is a reserved word, but And and AND are two different, valid names. As a convention, names starting with an underscore (such as _VERSION) are reserved for use by Corona.

Comments begin anywhere with a double hyphen (--) except inside a string. They run until the end of the line. Block comments are available as well. A common trick to comment out a block is to surround it with --[[ and --]]

1
2
3
--[[
print( 10 )       -- no action (comment)
--]]

To uncomment the code, add a single hyphen at the beginning of the first line:

1
2
3
---[[
print( 10 )       --> 10
--]]

A numerical constant can be written with an optional decimal part and an optional decimal exponent. Lua also accepts integer hexadecimal constants, by prefixing them with 0x. Examples of valid numerical constants are

     3   3.0   3.1416   314.16e-2   0.31416E1   0xff   0x56

Types and Values

Lua is a dynamically typed language. Unlike other languages, you do not need to declare the type of a variable; each value implicitly carries a type.

All values in Lua are first-class values. This means that all values can be stored in variables, passed as arguments to other functions, and returned as results.

The basic types that you’ll deal with are:

  • nil. Nil is a type with a single value, nil. By default, global variables are nil which means that they have not been assigned a value. This is analogous to null in JavaScript/ActionScript.
  • boolean. The boolean type has two values, false and true. Note that in conditional expressions, e.g. if ( condition ), both false and nil evaluate as false; everything else evaluates as true.
  • number. Represents real (double-precision floating-point) numbers.
  • string. Represents arrays of characters (any 8-bit character, including embedded zeroes)
  • function.
  • table. Tables are the fundamental data structure in Lua. They implement an associative array which is just a fancy way of saying that the array can be indexed not just by numbers, but also by any other value of the language except nil. Typically, you would use a string as an index (see Properties).

Conversions between string and number

Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert this string to a number, following the usual conversion rules. Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control over how numbers are converted to strings, use the format function from the string library (see string.format).

Objects

Tables and functions are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

Tables

Tables implement associative arrays, that is, arrays that can be indexed not only with numbers, but with any value (except nil). Tables can be heterogeneous; that is, they can contain values of all types (except nil). Tables are the sole data structuring mechanism in Lua; they can be used to represent ordinary arrays, symbol tables, sets, records, graphs, trees, etc. To represent records (a.k.a. properties), Lua uses the field name as an index. The language supports this representation by providing a.name as syntactic sugar for a["name"].

Like indices, the value of a table field can be of any type (except nil). In particular, because functions are first-class values, table fields can contain functions. Thus tables can also carry methods.

You can create tables using the table constructor which is written as {}:

1
2
3
4
5
6
7
8
9
        t = {}                          -- create a table
        k = "x"
        t[k] = 3.14                     -- new table entry, with key="x" and value=3.14
        t[10] = "hi"            -- new table entry, with key=10 and value="hi"
        print( t[k] )           --> 3.14
        print( t["x"] )         --> 3.14
        print( t.x )            --> 3.14
        k=10
        print( t[k] )           --> "hi"

Note in the above example, the entry with field name "x" was accessed in two ways: as a property using the dot operator t.x (line 7) and as an array item using indexing t["x"] (line 6).

A common mistake is to confuse t.x with t[x]. The first is equivalent to t["x"], or in other words a table indexed by the string “x”. The second is a table indexed by the value of variable x.

Variables

Variables are places that store values. There are three kinds of variables in Lua: global variables, local variables, and table fields. Any non-initialized variable is nil by default.

Global

Global variables do not need declarations. You simply assign a value to one to create it:

1
2
3
print( s )                                              --> nil
s = "One million dollars"
print( s )                                              --> "One million dollars"

Global variables live as long as your application is running. You can delete a global variable by assigning nil to it. At this point, the global variable behaves as if it were never initialized:

1
2
s = nil
print( s )                                              --> nil

Local

Local variables are declared using the local statement:

1
2
x = 1                                                   -- global variable
local y = 10                                    -- local variable

Unlike global variables, local variables are visible only in the block where they are declared. The scope of the local variable begins after the declaration and ends at the end of the block.

1
2
3
4
5
6
7
8
9
10
a = 10
local i = 1
 
while i <= 10 do
   local a = i*i                                -- different variable 'a' local to while block
   print( a )                                   --> 1, 4, 9, 16, 25, ...
   i = i + 1
end
 
print( a )                                      --> 10 (the global 'a')

Table fields (properties)

Table fields are just the elements of the table themselves. You index into the array to assign the values to a field. When the index is a string, the field is known as a property (see also Properties):

1
2
3
4
5
6
7
t = { foo="hello" }                     -- create table with a single property "foo"
print( t.foo )                          --> "hello"
t.foo = "bye"                                   -- assign a new value to property "foo"
print( t.foo )                          --> "bye"
t.bar = 10                                      --> create a new property bar
print( t.bar )                          --> 10
print( t["bar"] )                       --> 10

Expressions

Arithmetic Operators

Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), / (division), % (modulo), and ^ (exponentiation); and unary - (negation). If the operands are numbers, or strings that can be converted to numbers (see Conversions between string and number), then all operations have the usual meaning. Exponentiation works for any exponent. For instance, x^(-0.5) computes the inverse of the square root of x. Modulo is defined as

     a % b == a - math.floor(a/b)*b

That is, it is the remainder of a division that rounds the quotient towards minus infinity.

Relational Operators

The relational operators in Lua are

     ==    ~=    <     >     <=    >=

These operators always result in false or true.

Equality (==) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. Objects (tables and functions) are compared by reference: two objects are considered equal only if they are the same object. Every time you create a new object (a table or function), this new object is different from any previously existing object.

The conversion rules of strings and numbers do not apply to equality comparisons. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table.

The operator ~= is exactly the negation of equality (==).

Logical Operators

The logical operators in Lua are and, or, and not. All logical operators consider both false and nil as false and anything else as true.

The negation operator not always returns false or true. The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument. The disjunction operator or returns its first argument if this value is different from nil and false; otherwise, or returns its second argument. Both and and or use short-cut evaluation; that is, the second operand is evaluated only if necessary. Here are some examples:

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

Concatenation

The string concatenation operator in Lua is denoted by two dots ('..'). If both operands are strings or numbers, then they are converted to strings.

Length Operator

The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).

Precedence

Operator precedence in Lua follows the table below, from lower to higher priority:

     or
     and
     >     <     >=    <=    ~=    ==
     ..
     +     -
     *     /     %
     not   #     - (unary)
     ^

As usual, you can use parentheses to change the precedences of an expression. The concatenation ('..') and exponentiation ('^') operators are right associative. All other binary operators are left associative.

Properties

Many Corona API’s return objects. You are free to manipulate the documented properties of these objects just like you would on a table. You can even add your own properties provided you do not prefix any of your custom properties with an underscore (“_”). Ansca reserves the right to use any property name that begins with an underscore.

Like most languages, all properties can be accessed via the dot (“.”) operator. It's really just a convenient way to index into a table. In other words, we can access property foo of a table t using the dot operator (t.foo) or index into it using a string (t["foo"]); the result is the same.

Functions

Because functions can be variables, a table can store them as properties. This creates allows for very flexible uses of a table. It can be used to logically group a family functions into a table, e.g. the math library. It can also be used to make a table have object methods (instance methods).

Plain functions

Plain functions are just what you expect. You provide some arguments as input, the function performs some task, and depending on the function, some result is returned. Most functions are stored in tables as properties. For example, to calculate the sine of 100, we would write math.sin(100). Here, math is merely a table. The property sin is the actual function.

All of the Ansca libraries such as the display library similarly group functions into tables.

Object Methods

Objects in Lua are represented by tables. Display objects (rectangles, images, etc.) and the global Runtime object are all examples of objects. Like the math library, these objects similarly store object methods (a.k.a. instance methods) as properties. One key difference, however, is syntax. You need to tell Lua that you intend this function to be called as an object method, not just a plain function. To do so, you need to use the colon (“:”) operator instead of the dot (“.”) operator. This may be slightly different than what you are used to in other languages. Compare the syntax of Javascript and Lua:

JavaScript Lua
object.translate( 10, 10 ); object:translate( 10, 10 )

Dot vs Colon

What does the colon operator do? It is actually a shortcut. In most languages, an object method call is just like a plain function call except there's a hidden first argument to the function that is the object itself. This hidden argument is known as this in Javascript and self in Lua. Therefore, the colon operator is merely a shortcut to save you from extra typing. You could call an object method using the dot operator if you pass the object as the first argument:

Object call with dot Object call with colon
object.translate( object, 10, 10 ); object:translate( 10, 10 )

Comparison with Other Languages

If you have used other scripting languages, you should have no problem adjusting to Lua.

Memory Allocation

Devices have limited memory available for use, so care must be taken to ensure that the total memory footprint of your application is kept to a minimum.

To help you, Lua does automatic memory management. This means you can create tables, functions, etc. but there is no function to delete them. Instead, Lua automatically deletes them via garbage collection. It can even handle cyclic data structures. So most of the burdens of memory management such as dangling pointers and memory leaks are taken care of for you.

However, it is up to you to tell Lua what to consider garbage. For example, anything stored in a global variable is not considered garbage, even if your application never uses it again. Similarly, anything stored in a table or array will not be considered garbage. In both cases, it is up to you to assign nil to these positions. This ensures that their corresponding memory will not be locked and can be freed by the garbage collector.

For display objects in the display hierarchy, the situation is slightly different. In addition to nil'ing references to a display object, you must explicitly remove them from the display hierarchy before it can be considered garbage.

Common Syntax Errors and Notable Syntax Differences

Some differences in syntax between Lua and other languages are worth noting because they can help avoid compiler errors:

  • Semicolons. Whereas some languages require a trailing semicolon at the end of each statement (effectively a line of code), in Lua this is optional.
  • Braces. You may be used to using { and } to define variable scope. In Lua, you can do this by bracketing the code with do and end. Braces in Lua are interpreted as table constructors
  • If then else. If you come from C, Java, Javascript, etc., a common mistake you'll make in writing if and elseif statements is forgetting to append then to the end of the if/elseif test condition. Another common mistake is inadvertently using else if (note the space) when you really mean elseif.
  • Arrays. In Lua, arrays are 1-based. Technically, you can index into an array starting with 0. However, all Lua and Ansca API's assume that the first element of table t is t[1] not t[0].
  • ? : (ternary operator). Lua does not offer the equivalent to the C ternary operator a?b:c. The Lua idiom (a and b) or c (or simply a and b or c, because and has a higher precendence than or) offers a close approximation provided b is not false. For example, the Lua equivalent to max=(x>y?x:y) would be max=(x>y and x or y). Beware that this idiom fails to work if b is false.
  • Multiple return values. An unconventional but useful feature in Lua is the ability for function to return more than one result.
  • Multiple Assignment. Multiple assignments offer a convenient way to swap values. The statement x,y=y,x will swap x for y and vice versa.

Replies

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
eazyigz
User offline. Last seen 28 weeks 3 days ago. Offline
Joined: 21 Jul 2011

Seems like an interesting language. Although, I won't be able to get used to the ternary operator substitution as max=(x>y and x or y).