To Dot, or Not To Dot
When we tried to select a language to use in Modulo Code, Lua came up pretty high in our short list. Lua is a language invented three decades ago by a computer scientist in Brazil named Roberto Ierusalimschy. It is a simple yet powerful and flexible language. And the way it is built allows it to easily combine with other system. It is also extremely fast to run and comes with a robust debug library. These qualities make it an ideal language for game creation.
For those not super familiar with how a game is created, making a game is a bit like making a movie; the game designer would script the actors in the game, telling each one of them what to do in what order and for what situation. For production efficiency, the designer would write a program for each one of the actors in the game scene using a scripting language. Altogether the collective effect of having every actors in the scene doing what their scripts tell them to do creates something known as a gameplay for the game. Lua is often used by game designers as a scripting language of choice. In the gaming industry today, Lua is one of the most used scripting languages in the world. Popular games nowadays such as Roblox and World of Warcraft use Lua very extensively.
Unlike most other languages, Lua’s only supported type of data is called table. Table is a piece of memory that you can name it. Not just that, you can also add fields to a table, and give each field a name too. So a field named breed
on a table named dog
can be referred to in code as dog.breed
using a .
“dot” symbol as a way to separate the table’s name from its field’s name. When we assign a value to the field, in this case — a breed name, we would write dog.breed = "Great Dane"
for example.
Other than a field, Lua also allows a function to be added to a table. A function is a piece of code in the memory. For example, we could have a function called move
on the table dog
. So to call the function, we would then write dog.move()
, again using .
as a separator between the table’s name and the function’s name. The parenthesis ()
is there to give specific details or function parameters to a function call when we want to run it. In our sample so far, our function move
still has no parameter.
Now, imagine in order for the function move
to work correctly, the function needs to know the current position of dog
so that it can update it on the screen. And since there may be more than one dog
in the game, we want each dog to have its own distinct position so that they are not necessarily at the same place all the time. Naturally, we would want to add a new field in dog
called position
and make this positioning data a function parameter to the move
function. When we call the function to run, we would then write dog.move(dog.position)
. To make it even more interesting, each dog may move at a different speed, so a new field dog.speed
is added too.
It looks like it would be more prudent if, instead of appending yet another function parameter dog.speed
to the function and make the function call looks tediously long like dog.move(dog.position, dog.speed)
, we just give the function one parameter dog
so the function call is simply dog.move(dog)
!
Although the call dog.move(dog)
looks kind of neat, it begs the question — why should we have to type dog
twice still? The Lua’s designers realized that a function that is already part of a table tends to want to access other fields also in the same table. For this reason, they added what they casually called a “syntactic sugar” by allowing the use of another symbol :
the “colon” sign, with the table’s name instead of .
to shorten the typing. More specifically, they made it so that dog:move()
works just like dog.move(dog)
except that it requires less typing. Please know that programmers are known to hate doing the exact same thing multiple times.
Inside the function itself, Lua defines a reserved keyword self
to refer to the function’s containing table. So if we were to write an imaginary move
function with a parameter for the time passed, it may look like this:
function dog:move(time)
-- Update the dog's position according to the time passed and speed.
self.position = self.position + self.speed * time
end
which is exactly the same as this:
function dog.move(self, time)
-- Update the dog's position according to the time passed and speed.
self.position = self.position + self.speed * time
end
This design choice of Lua creates a dilemma for us as we designed Modulo Code. What is more confusing to our users — making them type redundant words but know to only do so sometimes, or telling them two different ways to create the same function differently? “To dot, or not to dot, that is the question.” indeed.
We ultimately decided on using the :
sign and Lua’s syntactic sugar because the code looks more natural to beginners. For the more advanced users, they can mix and match the way they want it, knowing what’s really behind the scene. And with that, to make E.D. move one step forward or to make a jump, one simply types ed:moveForward()
or ed:jump()
.
Hopefully this post sheds some light on our mental struggle to this age-old dilemma of our times. Right or wrong — “Be all my sins remembered.”