Wiki
Clone wikiCore / CodeaClasses
Back to Beyond the Codea in-app reference
Classes in Lua
Object-oriented programming (OOP) in Lua is the subject of Chapter 16 of Programming in Lua (1st Ed). The lua-users wiki also publishes a collection of links related to OOP in Lua.
Several object-oriented (OO) languages offer the concept of class. Lua does not have the concept of class. However, as discussed in Programming Lua (1st Ed), it is possible to emulate classes in Lua. Each object may have a 'prototype', which is an object where the first object looks up any operation that it does not know about. To represent a class, we create an object to be used exclusively as a prototype for other objects (its instances).
Classes in Codea
Codea comes with a built-in global function class()
that is used to emulate classes.
Adding a class to a Codea project
For convenience, the '+' in the top right of the Codea editor offers the option of 'Create a New Class'. If chosen, you are prompted by the Editor to type the name of the new class. By default, class names start with a capital letter.
If you choose the class name 'MyClass', for example, the Editor creates a new tab named 'MyClass', with the following code as a template:
MyClass = class()
function MyClass:init(x)
-- you can accept and set parameters here
self.x = x
end
function MyClass:draw()
-- Codea does not automatically call this method
end
function MyClass:touched(touch)
-- Codea does not automatically call this method
end
In the example above, the statement MyClass = class()
is executed before the setup()
function is called. The class()
function is built-in to Codea. Its Lua code is identified below.
For convenience, variables that are equal to class()
are then included in the autocomplete functionality of Codea's editor.
Using Codea's class() function
The following example shows the creation of an 'Animal' base class and a 'Dog' class that inherits from 'Animal'.
In an 'Animal' tab:
----------------
-- Class: Animal
----------------
Animal = class()
function Animal:init( word )
self.talk = word
end
function Animal:speak()
print( self.talk )
end
In a 'Dog' tab:
----------------
-- Class: Dog
----------------
Dog = class(Animal)
function Dog:init()
Animal.init( self, "Woof!" )
end
In the 'Main' tab:
----------------
-- Main
----------------
function setup()
-- Create a Dog
d = Dog()
d:speak()
-- Create an Animal (not a Dog)
b = Animal("Tweet!")
b:speak()
end
The example above works because Animal
has been created before Dog = class(Animal)
is executed. Codea reads in each file (tab) in order and executes everything that is outside of a function ... end
block.
If the example above is extended to include an 'Aardvark' class:
In an 'Aardvark' tab (which, by default, is placed alphabetically before the 'Animal' tab):
----------------
-- Class: Aardvark
----------------
Aardvark = class(Animal)
function Aardvark:init()
Animal.init( self, "Yap! Yap!" )
end
Added to the setup()
function in the 'Main' tab:
-- Create an Aardvark
a = Aardvark()
a:speak()
When this code is run, it results in an error message in the Output panel like:
error: error: [string "..."]:9: attempt to call method 'speak' (a nil value)
That is because Animal
has type nil
when Aardvark = class(Animal)
is executed.
If the 'Aardvark' tab is dragged after the 'Animal' tab, the code will run as expected.
Lua code for Codea's class() function
The Lua code for Codea's class()
function is set out below and here:
-- Class.lua
-- Compatible with Lua 5.1 (not 5.0).
function class(base)
local c = {} -- a new class instance
if type(base) == 'table' then
-- our new class is a shallow copy of the base class!
for i,v in pairs(base) do
c[i] = v
end
c._base = base
end
-- the class will be the metatable for all its objects,
-- and they will look up their methods in it.
c.__index = c
-- expose a constructor which can be called by <classname>(<args>)
local mt = {}
mt.__call = function(class_tbl, ...)
local obj = {}
setmetatable(obj,c)
if class_tbl.init then
class_tbl.init(obj,...)
else
-- make sure that any stuff from the base class is initialized!
if base and base.init then
base.init(obj, ...)
end
end
return obj
end
c.is_a = function(self, klass)
local m = getmetatable(self)
while m do
if m == klass then return true end
m = m._base
end
return false
end
setmetatable(c, mt)
return c
end
The function class
has a single argument base
and returns the table assigned to local variable c
. If class
is called as class()
, without an argument, then base
will be nil
.
The table c
has the following keys and values:
- if
base
is a table, a copy of the keys and values inbase
and a key_base
indexingbase
; - key
__index
indexingc
itself; and - key
is_a
indexing a function. The function takes two arguments,self
andklass
, and returnstrue
orfalse
.
The table assigned to c
has a metatable, being the table assigned to local variable mt
.
The table mt
has the following keys and values:
- key
__call
indexing a function returning the table assigned to local variableobj
. This function is called when a call is made on tablec
. The table assigned toobj
has a metatable, beingc
itself. Ifc
has keyinit
, then that is called withobj
as the first argument. Otherwise, ifbase
is notnil
andbase
has keyinit
, then that is called withobj
as the first argument.
Using the example of the 'Animal' class above, Animal = class()
assigns the table returned by the class
function to global variable Animal
.
The block:
function Animal:init(word)
self.talk = word
end
is equivalent to:
Animal["init"] = function (self, word) self.talk = word end
and the block:
function Animal:speak()
print(self.talk)
end
is equivalent to:
Animal["speak"] = function (self) print(self.talk) end
The right-hand side of the assignment b = Animal("Tweet!")
is a function call on the table assigned to Animal
and __call
comes into play. As Animal.init
is not nil
, Animal.init(obj, "Tweet!")
is called and, ultimately, a table is returned, and assigned to b
, with key talk
indexing "Tweet!" and with a metatable with key __index
set.
The statement b:speak()
is equivalent to b["speak"](b)
. Now __index
in the metatable of b
comes into play, and b["speak"]
returns the function Animal["speak"]
. That function is called with argument b
and, consequently, b.talk
is printed.
Example projects using Codea's class() function
How the class()
function can be used is illustrated in the following example projects provided with Codea 3D Lab, Physics Lab, Anagrams, Spritely, Bit Invader, Brick Out, Sounds Plus, Lua Jump, Dungeon Roller, and Ping.
Updated