The : operator

In the previous section, you implemented some object-oriented principles by building an enemy class, instantiating several enemies and calling some methods on the enemy instances. While all of the code was technically correct, each enemy instance had to be passed to the function stored in the enemy class.

Lua provides some syntactic sugar for calling functions on objects, the colon (:) operator.

This operator automatically provides the first argument to a function. This first argument, by convention, is called self. You can call this first argument whatever you want, but following convention will make your code easy to read and maintain.

The following bit of code demonstrates how the colon operator is used in comparison to the dot operator:

Vector = { 
x = 0,
y = 1,
z = 0
}

Vector.new = function (self, object)
object = object or {} -- Use provided table, or create new one
setmetatable(object, self) -- Assign meta table
self.__index = self
return object
end

Vector.print = function(self)
print("x:" .. self.x .. ", y: " .. self.y .. ", z: " .. self.z)
end

-- same as Vector.new(Vector, nil)
velocity = Vector:new()

-- Same as Vector.new(Vector, {x=20,z=10})
momentum = Vector:new({x = 20, z = 10})

-- Using the dot syntax, the print method of the
-- Vector class is called, and the object instance
-- is passed as it's first variable (self)
Vector.print(velocity)
Vector.print(momentum)

-- Using the colon syntax, the print method can be
-- called on instances of the Vector class. The colon
-- operator will fill in the first variable (self), with
-- the object instance it is being called on
velocity:print()
momentum:print()

The colon syntax makes calling the function more convenient. Remember, before this operator, each function had to be called on the Enemy table with the first argument being the Enemy table, like the following:

grunt = Enemy.new(Enemy)
boss = Enemy.new(Enemy, { health = 500, defense = 100 } )

Using the colon syntax, that is no longer needed. Because the Enemy table is on the left-hand side of the colon, it will automatically be provided as the first variable, in this case named self. The previous code could be rewritten as follows:

grunt = Enemy:new() -- self = Enemy
boss = Enemy:new({ health = 500, defense = 100 } ) -- self = Enemy

Using the colon operator makes calling member functions simpler as well. Before using the colon operator, the hit function had to be called on the Enemy class, with the first argument being the instance of the class to affect:

Enemy.hit(boss, 50)
Enemy.hit(grunt, 55)

The colon operator provides whatever is on its left side as the first argument to the function being called. This makes it possible to call methods on objects instead of the class:

boss:hit(50)
grunt:hit(55)

This code works because boss:hit(50) is just syntactic sugar for Enemy.hit(boss, 50). How does Lua know that the Enemy table has a hit function, not the boss table? Because the boss table's __index meta method points at Enemy. When Lua sees that boss.hit(boss, 50) is invalid but boss has an __index meta method, it tries to call the function using the meta method.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.237.194