Lua for ActionScript Developers: Crash Course

Skip Intro

Preface

I needed a break from Flex for mobile, and wanted to see if there were any other good application frameworks that allowed you to deploy to multiple devices beyond Adobe AIR. Tony Lukasavage had written about a few recently, and Matt Guest had written about his quick experience using Corona for games based on the buzz around Robert Nay, the 14 year old who knocked Angry Birds out of the top mobile game slot via Bubble Ball.

While Unity has the best language on the planet, C#, I needed a break from lower level languages.  In the past, Ruby and Python were great reprieves for doing smaller projects.  In doing some mobile apps, I’ve noticed that for the scope of the project, sometimes 3 weeks or less, the verbose language actually gets in the way.  So, I was looking for a higher level language, and Lua in Corona SEEMS to fit the bill, but I’m still learning.  I liked how I could save a file in TextMate and and it would just refresh the iPhone/Android emulator. HOTNESS! Uber fast compared to mxmlc and “Building…” in Flash Builder, even when using pure AS3.  The interpreted nature of Lua helps speed that up (I guess).

Introduction

I’ve only been reading up on Lua for 1 day, but here’s a quick crash course to get traditional ActionScript programmers up to speed with Lua concepts.  If you’ve done any ActionScript 1, or even JavaScript, you’ll find this very familiar to traditional ECMA concepts.  If you’re a Java/C guy coming to Flex and now reading this, it may be a little weird.

I’m still learning the OOP & packages Lua stuff, so will post that in a later article.  In reading the docs, it’s pretty clear OOP and packages aren’t really something the original language designers figured you’d actually do, so it seems like a ton of work, more than it took in AS1, to get inheritance and packages.

WARNING: This guide was written primarely to help me learn Lua and have all the common comparisons on one page.  I’m sure it has errors and misconceptions; if I get railed in the comments, I’ll update this post as soon as possible.  Here there be dragons, bitches!

Getting Started

If you’re on a Mac, the best thing to do is go download & install Corona + TextMate, and then install the Corona Bundle for TextMate.  For Windows users, you can check out more on their blog.

Output

To show output from your code in ActionScript for the Flash IDE’s console, or Flash Builder’s console, you use trace:

trace("Hello World!");

In Lua, you use print:

print("Hello World!")

You’ll notice there is no semi-colon used in Lua. Like ActionScript they are optional, but most code I’ve seen doesn’t use them. I’ve only met 1 ActionScript coder that didn’t use semi-colons.

There are also no brackets {} in Lua, similar to Python, although the whitespace isn’t as strict.

Comments

In ActionScript, a single line comment is //:

// This is a comment ActionScript

In Lua, a single line comment is: —

-- This is a comment in Lua

A multi-line comment in ActionScript starts with /* and ends with */:

/*
This is a
multiline comment
in ActionScript
*/

In Lua, it starts with –[[ and ends up ]]–:

--[[
This is a
multiline comment
in Lua
]]--

Variables

In ActionScript 1, this was a global variable:

_global.foo = "bar";

In Lua, this is a global variable:

foo = "bar"

In ActionScript 3, you usually have to utilize the Singleton design pattern or a default namespace class to get globals:

package
{

	public class MyGlobals
	{

		public var foo:String;

		private static var _inst:MyGlobals;

		public function get instance():MyGlobals
		{
			if(_inst == null)
				_inst = new MyGlobals();

			return _inst;
		}
	}
}

// then to use
MyGlobals.instance.foo = "bar";

…or a public static variable on MyGlobals:

package
{
	public class MyGlobals
	{
		public static var foo:String;
	}
}

// then to use
MyGlobals.foo = "bar";

In ActionScript 3, un-initialized variables on non-dynamic objects such as classes such as Strings or other by reference variables are null:

trace(foo); // null
foo = "bar";
trace(foo); // bar

Lua uses nil:

print(foo) --> nil
foo = "bar"
print(foo) --> bar

To remove a reference on a strongly-typed object in ActionScript 3, you set the variable to null:

myArray = [1, 2, 3];
myArray = null;

In Lua, you set it to nil:

myNumber = 10
myNumber = nil

Notice I used a Number in Lua. In ActionScript 1, you could do that since all were variants, but in AS3, you can’t set a Number to null, only another Number or NaN.

Lua (I think) has it’s own garbage collection like ActionScript 1 and 3 do, thus they both use null and nil to decrement the reference count on objects. Both have similar rules for immutable primitives, like String and Number always creating new variables, and this copying by value when you create new ones:

var a:String = "moo";
var b:String = a;
a = "whoa";
trace(a); // whoa
trace(b); // moo

Lua is the same way.

The reverse is true for Objects that use by ref such as Arrays/Lists and other Objects.

var a:Array = [1, 2, 3];
var b:Array = a;
a.pop();
trace(a); // 1,2
trace(b); // 1,2
trace(a == b); // true

So, while ActionScript 3 has certain rules for primitives such as String, Number, int, and uint, in Lua you can just set it’s String and Number (it only has Float) to nil.

Types

In ActionScript 1, most everything was a variant. In ActionScript 3, we have a true type system. In Lua, everything is basically a variant. In AS1, if you wanted to figure out the type of something, you’d use typeof:

var foo = "bar";
trace(typeof(foo)); // bar
var foo = 10;
trace(typeof(foo)); // number
trace(typeof(typeof)); // function

In Lua, you use type:

foo = "bar"
print(type(foo)) --> string
foo = 10
print(type(foo)) --> number
print(type(type)) --> function

Booleans & if tests

Keep in mind, nil and false always equate to false. Everything else is true. The use of 0 and “” are considered true in Lua, and in ActionScript. Sometimes people will use if in ActionScript to test for true or if a variable is not null:

if(foo)
{
  trace("foo is: " + foo); // bar
}
else
{
   trace("foo is null.");
}

Similar in Lua:

if foo then
	print("foo is: " .. foo)
else
	print("foo is nill")
end

Concatenation

Notice in ActionScript, + is used for concatenating everything in trace, and ActionScript is smart enough to coerce and/or call toString() on certain Objects.

trace("foo " + "bar"); // foo bar

In Lua, you use ..

print("foo " .. "bar") --> foo bar

Numbers/Floats

Numbers in Lua are similar to Numbers in ActionScript 1; they are floats (decimals). There are no ints or uints.

Tables vs Objects

Tables are the what Lua calls Objects. They have nearly the exact same syntax, although their constructors are completely different and have a ton of syntactic sugar in Lua. They’re basically associative arrays. You can use any value as the key in Lua, excluding nil.

var a:Object = {};
var k:String = "x";
a[k] = 10;
trace(a["x"]); // 10
trace(a.x); // 10
a = {}
k = "x"
a[k] = 10
print(a["x"]) --> 10
print(a.x) --> 10

To remove slots in ActionScript, you use delete:

delete a.x;

In Lua, you just set it to nil:

a.x = nil

Math

Math operations are about the same using +, -, *, / and standard math precedence/order of operations including parentheses ()… sort of. You can see the precedence in the docs.

Relational Operators

Lua has about the same operators as ActionScirpt excluding “not equal”.

 <   >   <=  >=  ==  !=
 <   >   <=  >=  ==  ~=

Notice the last one.

Logical Operators

ActionScript has:

&& // and
|| // or
!= // Borat says, "NNNooott!"

Lua has:

and --> and
or --> or
not --> not

So, from the Lua docs, here’s ActionScript:

trace(4 && 5);         // 5
trace(null && 13);         // null
trace(false && 13);         // false
trace(4 || 5);         // 4
trace(false || 5);         // 5

And Lua:

print(4 and 5)         --> 5
print(nil and 13)      --> nil
print(false and 13)    --> false
print(4 or 5)          --> 4
print(false or 5)      --> 5

Assignments and Statements

ActionScript and Lua have a similiar syntax for statements although ActionScript has more helper shortcuts like +=, ++, etc.

var a:Number = 1;
a = a + 1;
trace(a); // 2
a++;
trace(a); // 3
a = 1
a = a + 1
print(a) // 2
a = a + 1
print(a) // 3

You can also do single line with multiple variables; while un-readable to me, it actually comes into play when you have functions returning multiple values and error handling as you’ll see later.

a, b = 10, 2*x

For example, assuming getResults() returns 2 values instead of the standard 1 in ActionScript, you can get the first and second via:

a, b = getResults()

Yes, craziness.

Local Variables

Local variables in ActionScript:

var i:Number = 0;

function foo()
{
   trace(i); // 0
   var i:Number = 23;
   trace(i); // 23
}

And in Lua:

i = 0
local i = 1

Local variables are stricter in scope in Lua than in ActionScript. They are similar to how they are (I think) in C, where it’s “block based”. In ActionScript, the local variable is local to the entire function whereas in Lua, it’s local only to the current block it’s in, such as the then/else part of the if then statement. Finally, in both languages, local variables are faster to access.

An example of local scope in Lua is a while loop:

x = 10
local i = 1 --> local to chunk
while i < 2 do
   local x = i * 2 -- local to the while body   
   print(x) --> 2, 4, 6, 8, ...
   i = i + 1
end

The locals, like in ActionScript, aren’t actually created until you initialize them, so this makes for more efficient code.

Control Structures

Lua has the standard if, while, for, and repeat statements. The difference is the if, while, and for need a corresponding end for the statement. The repeats use an until statement.

Here’s a simple if statement in ActionScript:

if(a < 0)
{
   a = 0;
}

And Lua:

if a < 0 then a = 0 end

... or:

if a < 0 then
   a = 0
end

Here's an if else statement in ActionScript:

if(a < b)
{
   return a;
}
else
{
   return b;
}

And in Lua:

if a < b then
   return a
else
   return b
end

...that too can be written on one line.

Like Python, Lua has elseif:

if value == "north" then
   return y  - 1
elseif value == "south" then
   return y + 1
elseif value == "east" then
   return x + 1
elseif value == "west" then
   return x - 1
else
   error("invalid direction, yo!")
end

Notice we have the standard == to test for equality. The common way to report errors is the error function; we'll get to him in a bit.

Loops

A quick note about loops. In ActionScript, the first index of an Array or Vector is 0. In Lua, it's whatever you want, but the convention is 1. You can use 0 if you really want to, but a lot of the existing libraries may not work since they follow the 1 convention. Also there isn't a concept of "Array.length" in Lua. The first item found that has nil is considered to be "end" of the Array/List/Table.

While Loop (and Arrays)

For you while fans, here's one in ActionScript:

var i:int = 0;
while(list[i])
{
   trace(list[i]);
   i++;
}

And in Lua:

local i = 1
while list[i] do
   print(list[i])
   i = i + 1
end

Notice Lua starts with 1 whereas ActionScript starts with 0. Also notice the while loop in Lua is testing if list[i] is not equal to false or nil. The way Arrays (in this case a simple table acting as an associative array) work for most looping operations is you test for nil in them. If it finds nil, it assumes it is the end of the array/list.

For - 2 Types

There are 2 types of for loops. For loops are similar to ActionScript, but the syntax is quite different. Sometimes smaller loops are written on 1 line. You'll constantly see this in Lua because of it's Functional bent, a lot of people try to write as terse as syntax as possible. If you come from a Java/ActionScript 3 only background, you'll want to spread it out more. I'll do both below.

Lua's numeric version of for loop works in pseudo code like this:

for var=start,end,optionalIncrement do
   something
end

You don't need to include the increment; if you don't, it'll assume 1. Most for loops I've seen in ActionScript always use 1 anyway.

Here's how we loop through 1 to 10 in ActionScript:

for(var i:int=1; i < 11; i++)
{
   trace(i);
}

Here's how we do the same in Lua:

for i=1,10,1 do print(i) end

...or:

for i=1,10 do print(i) end

...or even:

for i=1,10,1 do
   print(i)
end

There are some strange things too. The var, or i in this case, is a local variable to the for loop. After the loop is done in ActionScript, you can reference it, but not in Lua.

Also, functions/expressions in the for loop itself for start/end/increment are only run once where as in ActionScript, the test & increment are done each loop.

Like ActionScript, if you want to abort the mofo, use break. If you want to break it down, use DJ Icey.

The generic for is like a for var n or a for each in ActionScript where you iterate over properties of an Object. This gets pretty deep in Lua, and they have a TON of different ways one can write iterators, using closures, coroutines, etc. I encourage you to briefly read the docs on generic for and hit the advanced stuff (advanced for me, heh) if you're into that kind of thing (*cough* Python developers *cough*).

Break and Return Placement

While break and return are similar to ActionScript, their placement is more strict. Both have to be right before the last part of a block (right above end, else, or until).

Functions

Functions in Lua are just like they are in ActionScript with some subtle rules about usage you can read more on. What I want to focus on is multiple return values which plays into how you do error handling/logging in Lua if you come from a Flash background.

It's called unconventional in the docs, but when all functions that run in protected mode (more on that later), return errors as the 2nd parameter, that's not unconventional, that's conventional.

Anyway, check out how the find string function looks in Lua:

 s, e = string.find("hello Lua users", "Lua")
print(s, e)   -->  7      9

The find gets the first index where it occurs and ends or nil if it can't find it. Notice how the first result is in s, and the second is in e. To do this yourself, you just return 2 values like so:

function fooByTwo()
   return 1, 2
end

uno, dos = fooByTwo()

Variable Number of Arguments

Lua has rest parameters like ActionScript has as well:

function showNames (...)
   for i, name in ipairs(arg) do
      print(i .. ":name=" .. name .. "\t")
   end
end

Notice the arg variable is a predefined variable in functions, much like arguments was in ActionScript 1. In ActionScript 3, we can name it whatever we want:

function showNames(... names)

Finally, you'll notice ipairs is used a lot as a sort of default iterator for loops.

Function Scope

You can read more about lexical scoping, closures, and all the other Functional stuff if you want, but I wanted to focus on Scope because it's bloody AS1's thisThing.owner/mx.utils.Delegate all over again. If you don't remember what I'm talking about, or you have no context, Keith talks about it and how to get around ActionScript 1's scoping challenges via the Activation Object and Mike Chambers elaborates on how closures work in AS3.

Before AS3, classes had their callbacks scoped to what object they were called from, not where they were defined; thus you had to give child objects pointers back to their parent classes.

Lua has the same deal with functions. I'll elaborate more in a future OOP article since I'm still learning, but here's how it works. Functions in Lua by default don't have a this or self. Much like Python, you have to pass in scope in a generalized fashion.

Static

So... here's how you do a static method(sort of) in ActionScript:

package
{
	public class Bar
	{
		public static function foo(a:String):void
		{
			trace("passed in var: " + a);
		}
	}
}

Bar.foo();

...and in Lua:

Bar = {}
function Bar.foo(a)
   print("passed in var: " .. a)
end
Bar.foo("Cow")

In Lua, like AS1, you delete your class objects, however, thus if I made an instance, and tried to call it, it'd cause an error:

b = Bar
Bar = nil
b.foo("Test") --> Error

Instance Methods

So how do we get "this" equivalent? In 2 ways; it depends on how you call the function. Remember, Functional people like carrying scope around like a magic gem... seems like a lot of work to me, but I grew into an OOP world so what do I know.

You'd refine the above to this:

function Bar.foo(self, a)
   print("passed in var: " .. a)
end

Then, you can call it in 2 ways, the first manual way:

b = Bar;
b.foo(b, "test")

Or the built-in way they have to do that for you:

b = Bar;
b:foo("test")

Notice the colon instead of the dot.

If you remember Object.prototype in ActionScript 1 where you had to manually add this inside all functions, it's very similar.

Classes

I'll get into classes and packages later... they are whack compared to what I'm used too. For now, here's 3 syntax variations you can do (this'll look familiar to you AS1 devs):

The object/table way:

Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end

Using the Lua table constructor way:

Lib = {
  foo = function (x,y) return x + y end,
  goo = function (x,y) return x - y end
}

And the common way I've seen in Cornoa (I think):

Lib = {}
function Lib.foo (x,y)
   return x + y
end
function Lib.goo (x,y)
   return x - y
end

Errors

Lua's runtime, at least from what I've seen in Corona, runs just like Flash Player 8 on down did. If the original AVM has an error, it aborts the current function and/or related stack items, and tries its best to proceed. You can run Lua where it'll output to the console (Terminal if on Mac), but you won't see the errors in your code unless you specifically trap/log them.

A common error check in ActionScript 3 is checking for null; since this is the one thing our mxmlc compiler (and the Flash IDE) isn't really good at finding since Flash often gets external data in it, and thus "garbage in, garbage out" comes into play.

if(UserFactory.getUser(xml) == null)
{
   throw new Error("Dude, our XML is whack, yo! ...or maybe our parsing code is lame.");
}

Lua can do something similar:

if not UserFactory.getUser(xml) then error("Dude, our XML is whack, yo! ...or maybe our parsing code is lame.") end

However, that's a pretty common operation in Lua, thus they have an assert function. If assert gets a false or nil back from the function, it'll raise an error with the string you pass in the 2nd parameter:

user = assert(UserFactory.getUser(xml), "Failed to parse user."),

If you don't raise your own error in functions, Lua will return nil by default. Otherwise, you can call the built in error function, passing in the reason for the failure as a string, simliar to throw new Error("that blowed up real good") in ActionScript 3. You'll be able to see this in the console/Terminal.

Thus, the common way to play it safe is to use assert. Remember before explaining how Functions can return 2 values, and by default will return the error, if any, as the 2nd parameter? This works naturally with assert (example below from the docs):

file = assert(io.open("no-file", "r"))
      --> stdin:1: no-file: No such file or directory

Notice you didn't have to write a 2nd parameter in the error function, it'll return and print automatically via assert.

Custom Error Handling

Lua has a try/catch equivalent as well. If you call error("Explosions") inside a Lua function, it can be caught via pcall which means "protected call". Using pcall, it'll return true if all is well, and false if an error occurred. In ActionScript, you'd go:

public function foo():void
{
	if(!allGoodInDaHoodDogwood)
	{
		throw new Error("ZOMG, Compton!");
	}
	else
	{
		return;
	}
}

try
{
	foo();
}
catch(err:Error)
{
	trace(err);
}

In Lua:

function foo()
	if not allGoodInDaHoodDogwood then
		error("ZOMG, Compton!")
	else
		return
	end
end

if pcall(foo) then
	-- no errors in foo
	print "They SHOOTIN'!!!... aw made you look, you slave to a page in my rhyme book."
else
	-- foo threw an error
	print "foo blew up"
end

Stacktrace

You can use

print(debug.traceback)

to see the stacktrace up to the point of execution.

Conclusion

As we can see, Lua has a lot in common with ActionScript, specifically ActionScript 1, JavaScript, and ECMA in general. There is much more to Lua than the above, and the above is just from 1 day of reading & playing. If you're not looking to totally rock your world when learning a new language, say ActionScript to Objective C, then I encourage you to check out Lua, specifically using the Corona resources I stated at the top of this article. When I figure this OOP and package stuff out, I'll write a follow up post.

Please feel free to post corrections in the comments; I'm obviously still new at Lua.

11 Replies to “Lua for ActionScript Developers: Crash Course”

  1. I’ve just started using Corona/Lua myself. I find it to be pretty enjoyable and not all that difficult to jump into and start coding. A lot of it is just picking up on the syntax differences.

    The thing I most struggled with is tables/objects/arrays/classes. As you write, a table is basically an associative array. More than that though, it is the only data structure mechanism in Lua. So, you can pretty much throw the terms array, class and object out. In Lua, it is all table. Still wrapping my head around that, I must admit.

    I really hope you wind up doing an article about OOP in Lua, as that is something that I have yet to see written from an AS developer point of view.

  2. Great post! Some things that struck me about going from AS3 to Lua:

    Multiple assignments are also handy for swapping values:

    local a, b = 5, 10
    print(a, b) — 5 10
    a, b = b, a
    print(a, b) — 10 5

    (Just reading code like that first line took a while; now I see other people’s Lua where they don’t do that and think, “so unreadable!”)

    You can skip the increment in a for loop if it’s going to be 1:
    for i = 1, 10 do
    print(i)
    end

    Also, I believe that iterators are automatically declared as local for any loop:

    for k in pairs(myTable) do
    print(k)
    end
    print(k) — nil

    And this one still drives me nuts:

    local foo = true
    print(“foo” .. foo)

    throws an error because you can’t concatenate a boolean. So you have to use tostring():

    print(“foo” .. tostring(foo))

    Darren

  3. Great article Jesse. For a while, I’ve been meaning to pick up Corona and try it out.

    But have you looked into AirplaySDK? (No relation to Adobe AIR, or Apple airplay). AirplaySDK is C++, compiled and packaged to multiple platforms. It’s used by some big players for mobile games. Some people are using it with a third party Lua library, and programming in Lua.

  4. The most use of Lua should be large games, but even C++ games, which of course a little bit fast and effective than AS3, in some cases using Lua could still have performance issues, I’m wondering how Lua can really benefit for Flash/Flex applications.
    Another problem is the Alchemy support, Adobe seems no longer have new update even no promise whether it will continue or not. Solutions with Alchemy would under risk especially Adobe might more efforts on mobile implementations as well as other marketing challenges.

  5. Great article, although I debate that the original authors of the language didn’t intend OOP. The concept of tables was written to be a very generic way to layer any type of functionality. OOP in LUA is pretty simple. You should be able to write your own OOP library in a few hours, or download one of the many available libraries to jump start your dev.

Comments are closed.