Fundamentals of Lua (Part 1)

Wow, I guess I never wrote one of these before! Time to change that. In this article series, I will present the fundamentals of the Lua programming language. In another series, I will introduce how Lua is used on Roblox. For now, let’s get familiar with just the language.

Lua is an embedded scripting language. It is embedded to allow developers/users to customize the behavior of a host program (on this blog, Roblox). Many games and programs embed Lua, such as Roblox, Photoshop, Factorio, Gary’s Mod, LÖVE, and many more.  You often see it in the context of modding games, but some games like League of Legends use it for game logic. It’s used a lot because it very lightweight and fast; this is mostly because it is programmed in C, a low-level programming language. Finally, the word “lua” is the Portuguese word for “moon”. Lua’s name should never be written in all caps (i.e. never LUA).

To run Lua code, you’ll need a program that embeds it and a means to run Lua source within that program. On this blog I use Roblox, but anywhere you can run Lua and get errors and output will do. Also, Lua for Windows provides an OK standalone Lua environment, but standalone scripts are not Lua’s strength. If you don’t already have a means of running Lua code, try using repl.it!


Comments

OK, time to take the first steps! Lua runs lines of code top-to-bottom in order, skipping comments. A comment is a section of Lua source that is ignored. It is useful for notes and explaining your code. Comments are started with two dashes ( ) and run to the end of the line:

-- This is a comment. It is for humans to read.

You can have a comment span multiple lines by using double square brackets:

--[[
Sometimes you have more to say, and need more
lines to say it in. Use double square brackets
to have a comment span multiple lines.
]]

I’ll use comments in examples to explain what’s going on (you should too!). Also note that comments can appear at the end of a line of code.


Variables

A variable is a named space in memory which we use to perform computations. A variable uses an identifier, an alphanumeric name that may also include underscores (_ ); they also cannot start with a number. Using an identifier and an equals sign (= ), we may assign a value to a variable:

-- Some variables assigned to some values:
name = "Ozzy"
score = 5
locked = false
rating = 4.5
-- Some more strange examples of legal variable names:
MAX_PLAYERS = 8
hasRedKey = false
Player2Name = "Adam"
__secret__ = "hidden"

Don’t worry about the values we’re assigning these variables to yet. I’ll get to that. When these lines are run, Lua allocates a section of memory to store each value in that variable. Later, we’ll refer back to the values we stored by using the identifiers in expressions. Finally, we can’t use any reserved keywords (e.g. if, while, and, or, true) as identifiers. We’ll get to those later.

When deciding on the name of a variable, make it short and accurate. The name should tell you what the data stored there represents. Be consistent in the way you pick variable names (e.g. always use camelCase or PascalCase). Avoid short non-descriptive variables!


Values

A value is some kind of data that is stored within a variable. They take many forms, but for now we’ll talk about numbersstringsbooleans and nil:

  • A number is a single numerical quantity. It can be an integer or fractional.
  • string is a sequence of characters. Essentially, it is how text is stored.
  • A boolean is a switch – either true or false.
  • The nil value represents a lack of value (this what uninitialized variables have)

When you write a value within your code, you write it as a literal value. It’s not terribly important, but I’ll use this phrase when talking about more complicated values. An example:

-- An example of a literal string written in code.
instructions = "This string is written literally in my code. It is a literal."

Output

We can use the print  function to inspect the value contained within a variable. Don’t worry too much about what a function is just yet; just know that we can run the print function by adding parenthesis ()  after it:

-- The classic message you see when first trying out languages
print("Hello, world")
-- This will output the value contained within "score"
score = 5
print(score)
-- I'll use "-->" to represent expected some expected output
print(name) --> "Ozzy"

The actual location of your output data will vary depending on your program of choice. For repl.it, you’ll see it on the right panel. In Roblox Studio, it will appear in the Output window. Often, we’ll want to print more than one piece of data at at time. A single call to print  can accept many values at once; separate these with a comma:

-- Print a string followed by the score
print("My score is", score)

Using this function will be very important for understanding how Lua manipulates values in expressions. Use it when you aren’t sure what is being produced from some computation.


Operators and Expressions

This is where the work gets done! An operator is a symbol that performs some operation on some values. The simplest example is + , which adds two numbers (unsurprisingly):

-- Add two numbers using +
print(2 + 3) --> 5

There are quite a few operators available to you in Lua. I don’t think it’s necessary I go into these in detail; they all perform simple tasks necessary in computations. Here is a plethora of operators and some example output:

-- Math
print(2 + 3) --> 5. Addition
print(5 - 3) --> 2. Subtraction
print(3 * 4) --> 12. Multiplication
print(16 / 4) --> 4. Division
print(2 ^ 5) --> 32. Exponentiation.
print(15 % 6) --> 3. Modulo (Gives you remainder of division)
print(2 + 3 * 4) --> 14. Multiple math operations
print((2 + 3) * 4) --> 20. Parenthesis overrides order of operations.
-- Boolean logic (order doesn't matter)
print(true and true) --> true. Logical AND ("both this AND that")
print(true and false) --> false
print(true or true) --> true. Logical OR ("either this OR that")
print(true or false) --> true
print(false or false) --> false
print(not true) --> false. Logical NOT (flip the value)
print(not false) --> true
-- String concatenation (aka combining two strings)
print("Hello" .. "Dolly") --> HelloDolly (note the lack of space)

I’d say the only complicated thing here is parenthesis and how they change the order of operations. Remember, each operator has a precedence – multiplication before addition, for instance. You can use expressions on the right side of an equals sign to reassign the value of a variable:

-- Initialize x.
x = 10
-- Add 5 to x.
x = x + 5
-- Display x's value by concatenating the string and the number
print("x is " .. x)

Conclusion

OK, that’s enough for now. You’ve learned comments, variables, valuesoutput and a handful of operators. and  Here’s a code snippet to demonstrate some of the topics in this article:

Example: Distance Between Two Points
-- Define point 1 and point 2 by their (X, Y) coordinates
point1_X = 1
point1_Y = 1
point2_X = 5
point2_Y = 4
-- Calculate the distance between the points
distance = ((point2_X - point1_X) ^ 2 + (point2_Y - point1_Y) ^ 2) ^ .5
-- Print out our points and the distance between them:
print("Point 1: (" .. point1_X .. ", " .. point1_Y .. ")") --> Point 1: (1, 1)
print("Point 2: (" .. point2_X .. ", " .. point2_Y .. ")") --> Point 2: (5, 4)
print("Distance between points: " .. distance) --> Distance between points: 5

Remember: raising a number to the 0.5th power is the same as taking the square root. We’re using parenthesis in the expression that calculates the distance between the points. We concatenate the numbers together with strings to form our final output.

Exercises

Try writing some Lua code that solves the following problems:

  1. Calculate the volume of a rectangular prism given its length, width and height. Solution
  2. Calculate the perimeter and area of a circle given its radius. Solution
  3. Given a number of party guestspizzas and slices per pizza, calculate how many slices each person should get so that everyone has the same number of slices. Also calculate the number of leftover slices. Hint:  math.floor(n)  will round n  down to the nearest integer (e.g. 2.5 becomes 2). Solution

That’s all for this part! Once you’re comfortable with the topics in this section, move on to Part 2 in which you’ll learn about control flow.

Author: Ozzypig

Roblox developer and computer scientist. I love all things coding and game design!