Someone holding a white round object that looks like the moon.

Getting started with Lua

It's not rocket science

Just like the Moon is constantly influencing planet Earth’s ocean tides, it is likely that, at some point, Lua influenced your navigation over the internet.

Today, we’ll embark on an adventure to uncover how this well-rounded scripting language born in Brazil, eclipses its competitors in terms of speed, size, and simplicity, making it a popular choice amongst applications such as Neovim, NGINX, Redis, World of Warcraft, Roblox, Adobe Photoshop Lightroom, and many more enterprise software.

Disk size matters

If someone ever told you that disk size doesn’t matter, I’m sorry to be the one giving you the bad news… but you’ve been lied to. Of course, not everything is lost since knowing how to use it properly does help a ton, however, take a look at this:

Disk usages example. Java 100.268 KB, Python 26.574 KB, Ruby 20.136 KB, Lua 366 KB

Yup. And by the way, it includes the documentation.

Take this tiny size and put it in a simple API, allowing for strong integration with code written in other languages. Mix it with a small memory footprint. Now make it a fast – if not the fastest – interpreted language (which could even surpass C in some cases when using LuaJIT), and POOF! The result you’ll get is the perfect language for embedded systems.

These are the main reasons why Lua is great for configuring software applications and in the gaming industry (most notably for giving users the ability to extend games with their own mods). Still, if Lua is lightweight, easy to embed into an application, versatile, and fast, then why the heck do we live in a world ruled by JavaScript, Ruby, or even Python instead?

Gentle introduction

Being flexible is a great quality in many different scenarios, but as you might already suspect, there’s no such thing as a free lunch.

From Lua’s website:

A fundamental concept in the design of Lua is to provide meta-mechanisms for implementing features, instead of providing a host of features directly in the language. For example, although Lua is not a pure object-oriented language, it does provide meta-mechanisms for implementing classes and inheritance. Lua’s meta-mechanisms bring an economy of concepts and keep the language small, while allowing the semantics to be extended in unconventional ways.

So, to answer the previous section’s question, while the mentioned languages are indeed more bloated, they and their ecosystems provide many out-of-the-box solutions, whereas languages aimed at simplicity tend to transfer complexity management to the developer. Like everything, you should consider the tradeoffs when choosing a technology.

Before we get into our Lua programming survival guide, I want to share 10 notable facts orbiting around the language alongside comments about each one. Hopefully, this keeps you intrigued instead of feeling as if you’re lost floating in space.

1. Array Indexes Start at 1 Instead of 0 (WHAAAT?)

Weird, I agree. But just like Twitter changing its name to X, you’ll get used to it. Eventually. Maybe. Ok, maybe not.

2. There’s a Single Data Structure: Tables

Arrays? Lists? Dictionaries? Hashes? In Lua everything is represented with tables. Don’t worry, we’ll make sense of it soon enough.

3. Global by Default

Variables are global by default, unless explicitly declared as local (and you do want to declare them as local in 99% of cases).

4. First-Class Functions and Closures

This means that functions can be stored in variables, passed to other functions, and returned in functions. Closures are also supported, allowing functions to capture and retain access to local variables from their containing scope.

5. Multiple Return Values

You read it right. Functions in Lua can return multiple values at once! This is somewhat similar to array destructuring in JavaScript. Awesome!

6. Dynamic Typing

Meh. If you like strongly typed languages – although not built-in – at least there are workarounds such as using annotations to help the language server with types it cannot infer, or using the LuaRocks package manager to install teal, which is a typed dialect of Lua similar to TypeScript.

7. No ++ or += Operators

Not the end of the world, but can get verbose and annoying pretty fast.

8. Garbage Collected

It uses automatic garbage collection to manage memory, which is common in higher-level languages, but implemented in a lightweight and efficient manner in Lua.

9. Coroutines

It has built-in support for coroutines, enabling cooperative multitasking. Coroutines allow functions to yield and resume execution, providing a way to handle concurrency.

10. Tail Call Optimization

In order to understand recursion, you must first understand recursion. Proper Tail Calls, as they are called by the official docs, allow functions to call themselves recursively without growing the stack.

How hard does it get?

We’re about to find out.

(If the syntax highlighting is broken, you can check it out here instead)

-- Single line comment

--[[
    Multi-line
    comment
--]]

codeminer = 42 -- This is a global variable

-- While loops
while codeminer < 50 do
  codeminer = codeminer + 1 -- No ++ or += operators
end

-- For loops
for i = 1, 5 do
  print("Iteration: " .. i) -- String concatenation uses the .. operator
  codeminer = codeminer + 1
end

-- Repeat loops
repeat
  codeminer = codeminer - 0.5 -- Numbers can be integer or floating point
until codeminer == 42

-- If clauses
if codeminer > 42 then
  print 'Hello World' -- You can only omit parenthesis if a function has a SINGLE argument that is a STRING!
elseif codeminer ~= 21 then -- ~= is not equals
  print("Double-quotes are also fine") -- Strings are immutable like Python
else
  codeminer = nil -- Undefines the variable for garbage collection
  codeminer = anUndefinedVariable -- This is not an error, the undefined variable evaluates to nil
end

local aBoolValue = false -- How to make a local variable

-- Only nil and false are falsy; 0 and '' are truthy!
if not aBoolValue then print('it was false') end

-- 'or' and 'and' are short-circuited. This is similar to ternaries in JavaScript
-- In JS, const ans = aBoolValue ? 'truthy' : 'falsy' would be equivalent to:
local ans = aBoolValue and 'truthy' or 'falsy' --> 'falsy'

x, y, z = 1, 2, 3, 4
-- Now x = 1, y = 2, z = 3, and 4 is thrown away.

-- Functions are First-Class, so they can be passed as arguments, returned, or be anonymous
local function makeLog(someLogFunction, myClosureValue) -- Functions also can be local/global
  local doubleValue = myClosureValue * 2 -- and support closures

  return function(message) someLogFunction(message .. doubleValue) end
end

local printLog = makeLog(print, 21)

printLog('Codeminer') -- prints Codeminer42

-- Functions can return multiple values
local function returnMultiple(first,...) -- and receive multiple arguments
  local second, third, _, fifth = ...

  return first, second, third, fifth
end

L, u, a, moon = returnMultiple(1, 2, 3, 4, 5, 6, 7, 8, 9)
-- L = 1, u = 2, a = 3, moon = 5

----------------------------------------------------
-- Tables
----------------------------------------------------
--[[
  Now, this is where it starts to get interesting.
  Tables are Lua's only compound data structure; they are associative arrays.
  So we can use them as 'dictionaries' or as 'arrays'.
 ]]

-- Array-like Tables
local aLuaArray = {"apple", "banana", "cherry"}
local length = #aLuaArray -- Use # to get the size/length of a table

for i = 1, length do
  print(aLuaArray[i]) -- Indices start at 1 !!!!!!!!
end

-- Dictionary-like Tables
local aLuaDictionary = {
  name = "Edy", -- Dict literals have string keys by default
  [3.14] = 'Pi', -- Almost anything can be used as a key, including booleans, functions, etc
  ['@!#$'] = true, -- Trailing commas are fine
}

print (aLuaDictionary.name) -- String keys can use js-like dot notation
print(aLuaDictionary[3.14]) -- Literal notation. Prints "Pi"
aLuaDictionary['@!#$'] = nil -- Removes this key from the table
aLuaDictionary.myGreatNewKey = {} -- Adds a new key/value pair

for key, val in pairs(aLuaDictionary) do -- Table iteration
  print(key, val)
end

This markdown idea was shamelessly stolen adapted from https://learnxinyminutes.com/docs/lua/.

Congratulations! You’re now a certified Lua programmer… Right?

Wrapping it up

If you have read this far (and I sure hope you have, because if you just skipped to this section, then what are you doing with your life, Billy? What caused you to have the attention span of a fruit fly making you soOoOo unable to just sit down and read a freaking blogpost from top to bottom? You always want things your way, the easy way, don’t you, Billy? Always looking for excuses and shortcuts. Hey!! Don’t you DARE looking away, Billy, I’m talking to you! But anyways…), you might remember that Lua is not a pure object-oriented language, but it does provide meta-mechanisms for implementing classes and inheritance.

Well, such feat is achieved through clever usage of Metatables and Metamethods. To some extent, they could be compared to JavaScript’s Prototypes, but actually are not quite the same.

I believe this is a topic that could get out of hand pretty quickly due to its complexity, so it probably deserves its dedicated post. There are also other more advanced topics like sandboxing, calling C functions, protected function calls, assertions, string pattern matching, and more.

Since I still have more practical Lua tips and tricks up my sleeve, a follow-up to this post might happen sooner rather than later, so stay tuned!

Cool Lua stuff

Game Engine
https://love2d.org/

A collection of packages and modules that implements a node.js style API for the luvi/lit runtime
https://github.com/luvit/luvit

A comprehensive, but not exhaustive, translation of upstream ReactJS 17.x into Lua
https://github.com/jsdotlua/react-lua

A Just-In-Time Compiler (JIT) for the Lua programming language
https://luajit.org/

Add additional context to your code and type checking
https://luals.github.io/wiki/annotations/

The compiler for Teal, a typed dialect of Lua
https://github.com/teal-language/tl

References

Programming in Lua by Roberto Ierusalimschy

https://www.lua.org/

https://learnxinyminutes.com/docs/lua/

We want to work with you. Check out our "What We Do" section!