Posted 30 March 2012 - 09:02 AM
Hello, mad1231999 here, and I wan't to speak out about whet I learnt. I think many people have been wondering: Why does some functions require a colon? And this is one of the things that I'll try to teach you guys! This tutorial will not have anything to do with turtles, or anything like that, so if you wanna learn about turtles(CC stuff in general), this is not the tutorial for you.
Tables are very useful, but they all behave the same way(mostly). This is where metatables are very good.
A metatable is a very powerfool tool, if used correctly. They allow you to change the immediate behaviour of tables. E.g. ig we have a table inside a table, like this:
To do this, we need write this code before the print statement:
That is probably the easiest thing to do with metatables, but it is still useful.
I will now show you some more advanced usages of metatables, and metamethods too.
I have written a program, which stores a person's data upon call:
Output of this program should look like this:
One of the best things about metatables, is that we can use Object Orianted Programming in Lua! This is a bit more advanced, so hang on.
First an example of OOP in Lua:
io.open() return a "file", which is actually a table. When calling a function in that file, we use @file:<function>(…). If this was not OPP, we would do it like this: <function>(@file, …).
In my example I will create a game character, with some properties. If these properties are not specified upon call, they will default to the standard state:
That was simple enough, now for making a character:
The output of this program should look like this:
In more advanced OOP, you will normally be able to change values on the fly, and that is what I'm gonna show you how to do now.
In this example, I will create a "prototype" called Dog, and put some functions inside it
The output of this program should look like this:
Now for some more advanced, and very useful ways of storing data. We will be using the 2nd program from this tutorial.
If we insert this on line 2:
It is good, because if we try creating a new guy, with a name that already exists, then why create a new guy and use more memory, when we can just use th old one?
In order to achive this, we must change a bit in the code. The code should look like this:
What we changed, is that whenever we try creating a new person, we check if that person already exists. If it does, we return the person that exists. If not, we create the person, and store it in the cache.
Thanks for reading this entire tutorial, I will add more along the way, as I learn more about metatables!
I really hope you liked it, and learnt something from it.
Please leave a comment, saying what you think, and if you think I should improve something.
Thanks
-mad1231999
Tables are very useful, but they all behave the same way(mostly). This is where metatables are very good.
A metatable is a very powerfool tool, if used correctly. They allow you to change the immediate behaviour of tables. E.g. ig we have a table inside a table, like this:
local t = {}
t._t = {str = "Hello World!"}
We could set the default "address" to the @_t table, so if we did this:
print(t.str)
Even though the @str variable is in @t._t, and we are calling it through t@, it would still print "Hello World!".To do this, we need write this code before the print statement:
local mt = {__index = t._t}
setmetatable(t, mt)
Now, when we run our program, it should print "Hello World!". Link to full program.That is probably the easiest thing to do with metatables, but it is still useful.
I will now show you some more advanced usages of metatables, and metamethods too.
I have written a program, which stores a person's data upon call:
local getPerson = {}
local mt = {
__call = function(table, _name, _age, _gender) --Creating the __call function, which gets called everytime we call the table
local person = {name = _name, age = _age, gender = _gender} --Passing the parameters into the person
return person
end
}
setmetatable(getPerson, mt)
local john = getPerson("John", 27, "male") --The __call function gets triggered
print(john, "njohn's name: "..john.name.."njohn's age: "..john.age.."njohn's gender: "..john.gender.."n") --We get a table with the values name, age and gender
Output of this program should look like this:
table: --Random numbers and letters
john's name: John
john's age: 27
john's gender: male
One of the best things about metatables, is that we can use Object Orianted Programming in Lua! This is a bit more advanced, so hang on.
First an example of OOP in Lua:
io.open() return a "file", which is actually a table. When calling a function in that file, we use @file:<function>(…). If this was not OPP, we would do it like this: <function>(@file, …).
In my example I will create a game character, with some properties. If these properties are not specified upon call, they will default to the standard state:
local Man = {}
Man.default = {name = "Noname", strenght = 100, speed = 67} --Creating a table with the default properties
Man.mt = {__index = Man.default} --Creating the metatables, which will index to Man.default
function Man:new(t)
setmetatable(t, Man.mt)
return t
end
That was simple enough, now for making a character:
local man = Man:new({speed = 5}) --Creating an instance of Man, called man
print("Man's speed: "..man.speed) --Print all the properties of @man
print("Man's strenght: "..man.strenght)
print("Man's name: "..man.name)
Link to full programThe output of this program should look like this:
Man's speed: 5
Man's strenght: 100
Man's name: Noname
In more advanced OOP, you will normally be able to change values on the fly, and that is what I'm gonna show you how to do now.
In this example, I will create a "prototype" called Dog, and put some functions inside it
--Most of this should be familiar
local Dog = {}
Dog.__index = Dog
function Dog.new(_name, _sound)
local dog = {}
setmetatable(dog, Dog)
dog.name = _name
dog.sound = _sound
return dog
end
function Dog:speak() --This is where it gets abit tricky
print(self.name..": "..self.sound) --When using @self, we are reffering to the instance used in Dog's place upon call
end
function Dog:setName(_name)
self.name = _name We are setting the name of the instance used to the parameter @_name
end
function Dog:setSound(_sound)
self.sound = _sound
end
local dog = Dog.new("DoggyBoy", "Bark") --Creating an instance of Dog called dog
dog:speak() --Calling dog:speak() and changing properties
dog:setSound("Hello World!")
dog:speak()
dog:setName("CoolGuy")
dog:speak()
The output of this program should look like this:
DoggyBoy: Bark
DoggyBoy: Hello World!
CoolGuy: Hello World!
Now for some more advanced, and very useful ways of storing data. We will be using the 2nd program from this tutorial.
local getPerson = {}
local mt = {
__call = function(table, _name, _age, _gender)
local person = {name = _name, age = _age, gender = _gender}
return person
end
}
setmetatable(getPerson, mt)
local john = getPerson("John", 27, "male")
print(john, "njohn's name: "..john.name.."njohn's age: "..john.age.."njohn's gender: "..john.gender.."n")
If we insert this on line 2:
getPerson.cache = {}
We will now have a cache for our table. Now, how can we use this? I'll tell you. But first: Why is this good?It is good, because if we try creating a new guy, with a name that already exists, then why create a new guy and use more memory, when we can just use th old one?
In order to achive this, we must change a bit in the code. The code should look like this:
local getPerson = {}
getPerson.cache = {}
local mt = {
__call = function(table, _name, _age, _gender)
if table.cache[_name] then return table.cache[_name] end
local person = {name = _name, age = _age, gender = _gender}
table.cache[_name] = person
return person
end
}
setmetatable(getPerson, mt)
local john = getPerson("John", 27, "male")
print(john, "njohn's name: "..john.name.."njohn's age: "..john.age.."njohn's gender: "..john.gender.."n")
local _john = getPerson("John")
print(_john, "n_john's name: ".._john.name.."n_john's age: ".._john.age.."n_john's gender: ".._john.gender.."n")
Now, when we run the program the output should be like this:
table: --Random numbers and letters
john's name: John
john's age: 27
john's gender: male
table: --SAME random numbers and letters as before
_john's name: John
_john's age = 27
_john's gender = male
What we changed, is that whenever we try creating a new person, we check if that person already exists. If it does, we return the person that exists. If not, we create the person, and store it in the cache.
Thanks for reading this entire tutorial, I will add more along the way, as I learn more about metatables!
I really hope you liked it, and learnt something from it.
Please leave a comment, saying what you think, and if you think I should improve something.
Thanks
-mad1231999