Lua for GrandMA3 Episode 4 - Building Tables in Lua

 Hey lighting folks! The following is the transcript from my YouTube video, Lua for MA3 Ep 4 - Building Tables in Lua

This video is part of my Lua for GrandMA3 Tutorial series. Please check out my channel, From Dark To Light, on YouTube, and you can find the code to go along with my tutorials here on GitHub.

Hello lighting people! Welcome back to my Lua for GrandMA3 tutorial series. Time to make a trip to the hardware store ‘cuz we're going to be building tables today! Wait – whoops. Wrong kind of table. These ones are not made with a hammer and nails, and you can't eat, do crafts, or set your lighting console on them either.

Instead we're going to be talking about a Lua tool called a table that is one of the most powerful tools in Lua and it can be used to sort, organize, label, and retrieve data really easily. If you've used other programming languages you may think of them similarly to arrays; but the concept is more similar to the arrays of Java and Scheme than C or Pascal – apparently. To be honest, I don't know any of those languages, but that's what the book Programming in Lua says, so I'll take their word for it.

Now for our use of tables in Lua there's not actually a lot that you can do in Lua without tables, so I used them for a long time without actually understanding how they worked, and that resulted in me often programming things in the hardest way possible. Obviously that's not very ideal, so I'm going to help you skip that part of the journey and start off strong with a clear understanding of tables before we start using them. Let's get to it.


So what exactly is a table? First off, it's neither a variable nor is it a value. Programming in Lua defines it as an object, so you can think of it as an object, just like your physical table. Or the way I like to think of it is as a container that holds data. That's technically what a variable is, but the difference is that a table can hold compartmentalized data – labeled, separated, and neatly stored.

A table contains keys and values in pairs; so for every key there is a value. A key is like the identifier for the value, or the name that refers to the value.

A table is actually anonymous by default, unlike a variable, which can only exist if it has a name, a table can be used, for example, in an argument, without actually defining a name for it.

Most of the time though, you are going to use a variable to reference the table; so I'm going to go into Visual Studio Code and make a table to show you how it works.


I'm going to make a table; I'm going to call it “myTable” and my table is going to be looking like this. That is a table. That's it. Of course, this is an empty table.

You can put values into the braces straight away, or you can create it with empty braces and insert values later, or you can add values when you create it and still add more later. There are lots of options.

Like I said, you arrange the table in keys and values; so every value has to have a key. A key can be either a string or a number, and if you use a variable it will interpret it as the string or number it references.


There are several ways you can add data to a table. One is when you create it, so I'll add a key/value pair to the table I just created, right where I created it. So I have “myTable is equal to” – I'm going to put “a = 1.”

Now my table contains a value called “a;” that is, the key is “a” and the value is 1. Now this “a” looks like a variable, but believe it or not it's actually read as a string, and there's no way to use a variable or a number as a key when you add values to a table this way.

Now I've made this table; let's say a little later down the road I want to add another piece of data to my table with the key “b.”

I can do it like this. I'm going to use square brackets and put in quotes “b = 2.”

When you add data this way, however, the string “b” that is being used as a key has to be written in quotes, otherwise it's read as a variable and currently the variable “b” doesn't exist so it would just be nil – you can't set a table key to nil.

Now if I were to try to add data using braces like I did before it would overwrite rather than add to my table, but just like when I used the braces to originally make the table, this method right here sets the value in table “myTable” at key “b” equal to 2. This method works no matter whether the key is a string, a number, or a variable referencing one or the other.

There is another method that again only works if the key is a string, and that looks like this. “myTable.c = 3” so in this case “c” is the same as if I put a c right here. It's the same thing; it's a string, it's not the same as myTable[c] in brackets; that would be using c as a variable again.


Now one thing about table keys or indices that is important to understand is that you don't have to define them like I have so far. If you want to know for sure what the key is it's useful to do so (it's called giving the key a name or creating named table values), but you can also simply insert a value or several at a time, separated by commas, and it will automatically number them starting with 1 and going up.

For example I'll create another table. This one's called “MyNewTable” and it's going to be equal to 1, 2, 3. So in this case I have index 1 has the value 1, index 2 has the value 2, index 3 has the value 3 – maybe a better example would be 10, 20, 25, just to be different. Index 1 has the value 10, index 2 has a value 20, and index 3 has a value 25.

There's also another way that you can add to tables that only works with numeric indices so here's how that one works. “table.insert()” and you're going to put an “x,” a “y,” and a “z” value in here, where “x” is the name of the table that you're inserting into, “y” is the index where you want the value to be inserted, and “z” is the value you wish to insert. y is actually optional so if you leave it blank z will be inserted into the next unused index in the table. And you cannot specify y as an index that doesn't yet exist unless it is 1. Also if you insert a value at index y it will move the old y and those following it up by one index each; so in other words, to actually use this in a way that makes sense, I'm going to go, “table.insert(MyNewTable…)” value “2,” or sorry, index “2,” and I'm going to put the value as “A Value,” just a string here; obviously that value can be anything; it can be a number or it can be a string, by the way even with this one, like these can be strings, they can be variables, they can be whatever you want them to be – they can even be other tables.

So basically in this case this inserts a value at index 2. So then whenever you try to read this table 10 is going to be at index 1, the string “A Value” is going to be at index 2, 20 is going to be at index 3, and 25 is going to be at index 4.


Okay, this is all great for creating tables, but how do we retrieve the information we've so carefully stored away in the table? The good news is, it's exactly the same syntax used to store it, so just use “table.index” or “table[index]” like this, anywhere you wish to use that value.

Do not try to print the table as a whole because a table is an object, not a value, and while values can be printed, objects can't, since obviously we don't have 3D printers in our command line or anything.


I understand there are so many different syntaxes and the rules for setting and calling table values and remembering strings versus variables versus numbers, which ones can be written in which way, can be very confusing, so I've actually made a table info example file you can find on GitHub, and I'll link that as well to refer to at any time. Hopefully that will help. By the way, these double dashes here let you put comments in the code, so just, anything beyond the double dashes is commented out and the program does not read it when it's going through the code; it's just for you to read to see information and you can use these at any time in any Lua program. I use comments pretty heavily and really most people do because it's not necessarily easy to remember what everything means when you write a big program and having comments to remind yourself “oh I did this for this reason” or “this is what this function does” is super helpful.


Okay, I'm going to show you one brief example of storing and retrieving table values just so you can see how it works. I'm going to create a table called “mySequence” and I'm going to give it a value called “name” and make that a string, “Test,” and then I'm going to give it a value called “ID” and set that equal to 1, and now I'm going to create a command, CmdIndirectWait like I showed you in the last video, and this one's going to say, “’Store Sequence ’ .. mySequence.ID ..” – I'll tell you in a minute what these dots mean – “’ /noconfirm; Label Sequence ’ .. mySequence.ID .. ‘ “’ .. mySequence.name .. ‘”’
Alright, now, these dots, like I said, they actually mean to concatenate two things, and what that means is, it just, like, connects them together, so if you concatenate two strings that turns them into one string, and that's basically what's happening here, so we're going to – if you read this command the way it's actually going to appear in the program, it's going to say “Store Sequence mySequence.ID,” so it takes the value in the table “mySequence” at the index “ID,” that would be 1, so “Store Sequence 1 /noconfirm; Label Sequence,” again, “mySequence.ID,” so that's 1, and then we put another single quote, space, double quote, so that MA3 can read it properly, and then concatenate the name “mySequence.name,” which would be “Test,” and then another double quote here so that MA3 can read it as a string as well.

Obviously that doesn't matter in this case cuz it's only one word; if it was multiple words or it had a space MA3 would need those quotes to be able to read it properly, but that's going to interpret it that way, and so that's the way this works. The only thing I will say about concatenation is, anytime you're trying to concatenate a nil variable that, that is, well, anything that's equal to nil, you're going to get an error and your whole plugin will just stop working, so make sure you're never trying to concatenate a variable that you don't know has a value.

Now I'm going to take this and put it in MA3 and run it so that you can see all of that and, as you can see, “Store Sequence 1,” and we labeled sequence 1 “Test,” so that worked properly; we had no issues with that.


Now in the next video I'm going to show you how you can take these values that are currently baked into your plugin; you know, the ID and the name, and let the user define them instead. Yes, you can actually ask the user for the name and ID and then quickly store a sequence based on their answers; and there are lots of other things you can do too, like there are all kinds of actions you can do based on user input, and it's really exciting; you're going to absolutely love it.

So the next video is going to get into some of that and it's going to involve one of the most common uses I have for tables, that is, a really awesome MA3 function called MessageBox. This is like Confirm, but on steroids; it's super powerful and very customizable. I use it all the time because you can do so many things with it, from custom text boxes and inputs to all different types of buttons, but you can also use it more simply without as much customization, making it quick and easy to add to any plugin. It will be called using a table as an argument and also returns values in the form of a table. Everything you learn today is going to make them make so much more sense, and since I don't think I have a single plugin I use regularly that doesn't include at least one MessageBox I can promise that understanding it well is going to help you more than you could possibly dream. So I'll see you in the next video; until then, happy lighting!


Comments

Popular posts from this blog

Lua for GrandMA3 YouTube Crash Course

Intro to Lua for GrandMA3

How to Make a Reminder Plugin for GrandMA3 Using Lua