From Ruby to Lua

Getting to know Lua, a powerful, fast, lightweight, scripting language.

I’ve been meaning to take a closer look at Lua for quite some time now. It has been described as a proven, robust programming language that is considered to be fast, portable, embeddable, powerful (but simple), small and free.

Sounds good to me.

Similarities with Ruby

Let’s start off by listing some of the characteristics shared between Ruby and Lua:

  • Dynamic type system
  • Closures
  • Non-significant whitespace
  • The use of nil to represent null values
  • All values are true, except nil and false
  • Created in 1993

How is it different from Ruby?

A lot of things differ between the two languages, here are a few of them:

  • Out of the box, Lua does not have a class system… but you are welcome to write one
  • Comments begin with -- instead of # (Like in Ada, Eiffel, Haskell and SQL)
  • Concatenation is done with .. instead of +
  • Functions may return multiple return values (Like in Go)
  • Function calls require parentheses () (Unless the function takes a single argument that is either a string or a table)
  • There is a length operator #
  • No interpolation of variables inside strings…
  • The existing string libraries assume single-byte characters :( but you can fix that, sort of
  • Variables are global by default, unless they are declared as local
  • Lua array indices count from one
  • Proper Tail Calls are supported.
  • No implicit returns :(

NOTE: MRI supports Tail Call Optimization if you change :tailcall_optimization to true in the compile options for RubyVM::InstructionSequence. This is unfortunately not part of the Ruby spec.

Installing Lua

If you are using OS X and have Homebrew installed, then you can install Lua like this:

$ brew install lua

Ubuntu users should install the lua5.1 package. (5.2 is the latest version, but it seems like there are compatibility issues with it and LuaRocks, YMMV)

Stuck on Windows? Then you’ll probably want to install Lua for Windows.

Package manager

In Ruby land we have the wonderful RubyGems. The Lua counterpart is called LuaRocks and it seems pretty neat.

Syntax

As is customary, let’s start with a Hello World program:

print("Hello World")

Nothing too surprising really. (You don’t strictly need the parentheses in this contrived example)

Variables and Blocks

Variables in Lua are global by default, but you can make them local to the current scope by prepending local like this:

do
  local answer = 42
  print("The answer to everything is: " .. answer)
end

print(type(answer)) -- nil

Unlike global variables, local variables have their scope limited to the block where they are declared.

A block in Lua creates a new scope.

Function definition

Defining a function in Lua is pretty straight forward, just as long as you remember to write function instead of def :)

function f(para1, para2)
  -- code
end

Anonymous functions

Unfortunately, anonymous functions in Lua is a bit unwieldy, I’d really like something similar to the lambda literal (stabby lambda) in Ruby.

var = function(param)
  -- code
end

Conditional expressions

C-style conditional expressions are not supported, but you can use and/or to emulate this.

function example(check)
  print(check and 'foo' or 'bar')
end

example(true) -- "foo" since check is truthy
example()     -- "bar" since check is nil

Built in functions

Lua has some built in functions that are available from the top level scope, a few of them are:

The type function gives the datatype name of a given value

print(type("dragonfruit")) -- "string"
print(type(3.5))           -- "number"

# gives you the size of a string, list, etc.

print(#{1,2,3}) -- 3
print(#"a str") -- 5

The loadstring function allows you to evaluate a string

I’m not sure if you ever want to do this.

loadstring('print("result: " .. 1+1)')() -- "result: 2"

Let’s write a small script using the Penlight Lua Libraries

First we need to install Penlight:

$ luarocks install penlight

Now we are ready to write our little example script. (Based on the uFAQ section 2.2 How to Parse command-Line arguments?)

scale.lua

#!/usr/bin/env lua

require 'luarocks.loader'

-- require is now aware of LuaRocks
require 'pl'

-- configure the Lapp Framework options parser
local args = lapp [[
Does some calculations
  -o,--offset (default 0.0)  Offset to add to scaled number
  -s,--scale  (number)  Scaling factor
   <number> (number )  Number to be scaled
]]

print(args.offset + args.scale * args.number)

The script requires the LuaRocks loader, loads the Penlight rock, configures the Lapp options parser, and finally it prints the result of the calculation offset + scale * number

$ lua scale.lua -o 5 --scale=10 20
205

A few projects based on Lua

MoonScript

A dynamic scripting language that compiles into Lua. It gives you the power of one of the fastest scripting languages combined with a rich set of features.

LuaJIT

LuaJIT is a Just-In-Time Compiler (JIT) for the Lua programming language.

Busted

Busted is a unit testing framework with a focus on being easy to use. Busted works with Lua >= 5.1, MoonScript, and LuaJIT >= 2.0.0

Codea

A pretty cool development environment for the iPad, built on top of Lua.

Redis

Yes, that is right… you can EVAL Lua code in Redis since version 2.6.0. You might want to read the article Lua: A Guide for Redis Users

Try Lua

An online REPL for Lua.

Games

There is also a lot of games using Lua for scripting

Learn more about Lua