{ |one, step, back| }

The Shape Example in Lua

Contributed by Marcelo da Silva Gomes

Lua is a simple procedural language, with only one data structure called Table (a set of key/value pairs). Keys and values can store any value, including functions. This data structure is flexible enough to be used as an array, a dictionary/hash/map or... an object!

Objects in Lua are just tables containing keys associated with strings, numbers, etc (attributes) and keys associataed with functions (methods). Attributes can be defined and accesed with '.' and methods with ':' (this is a sintactic sugar to create a function with an implicit self argument)

Inheritance can be implemented using the concept of metatables, that act like superclasses, and the setmetatable() function. The __index key stores the metatable of the table.

When a "method" is called, Lua searches for it in the table. If nothing is found, the search continues in the metatables.

Code for Lua

File: shapes.lua

-- Shape
Shape = {}

function Shape:new(newX, newY)
    local newShape = {x = newX, y = newY}
    setmetatable(newShape, {__index = Shape})
    return newShape
end

function Shape:moveTo(newX, newY)
    self.x = newX
    self.y = newY
end

function Shape:rMoveTo(deltaX, deltaY)
    self:moveTo(self.x + deltaX, self.y + deltaY)
end

function Shape:draw()
end


-- Rectangle
Rectangle = {}
setmetatable(Rectangle, {__index = Shape}) 

function Rectangle:new(newX, newY, newWidth, newHeight)
    local newRectangle = {x = newX, y = newY, width = newWidth, height = newHeight}
    setmetatable(newRectangle, {__index = Rectangle})
    return newRectangle
end

function Rectangle:draw()
    print(string.format(
        "Drawing a Rectangle at:(%d,%d), width %d, height %d", 
        self.x, self.y, self.width, self.height
    ))
end


-- Circle
Circle = {}
setmetatable(Circle, {__index = Shape})

function Circle:new(newX, newY, newRadius)
    local newCircle = {x = newX, y = newY, radius = newRadius}
    setmetatable(newCircle, {__index = Circle})
    return newCircle
end

function Circle:draw()
    print(string.format(
        "Drawing a Circle at:(%d,%d), radius %d", 
        self.x, self.y, self.radius
    ))
end


-- create a collection containing various shape instances
shapes = {Rectangle:new(10, 20, 5, 6), Circle:new(15, 25, 8)}

for i, shape in ipairs(shapes) do
    shape:draw()
    shape:rMoveTo(100, 100)
    shape:draw()
end

-- access a rectangle specific function
rectangle = Rectangle:new(0, 0, 15, 15)
rectangle.width = 30
rectangle:draw()

Output

Drawing a Rectangle at:(10,20), width 5, height 6
Drawing a Rectangle at:(110,120), width 5, height 6
Drawing a Circle at:(15,25), radius 8
Drawing a Circle at:(115,125), radius 8
Drawing a Rectangle at:(0,0), width 30, height 15