# Object Orientation Closure Approach

## Caveat

This is comparing a closures for objects approach with an extremely naive table based object approach. In most cases it would be considered idiomatic to make the methods for mariner objects part of a metatable so that each mariner instance would not require a hash for all the functions. This key design point means the memory comparisons below are not useful at all. The memory overhead for the closure approach will clearly be much less favorable compared to the sane method for implementing objects with tables.

## Intro

Please read the page mentioned above first to understand the differences of alternative method.

The most common OOP way in Lua would look like this:

```mariner = {}

function mariner.new ()
local self = {}

self.maxhp = 200
self.hp = self.maxhp

function self:heal (deltahp)
self.hp = math.min (self.maxhp, self.hp + deltahp)
end
function self:sethp (newhp)
self.hp = math.min (self.maxhp, newhp)
end

return self
end

-- Application:
local m1 = mariner.new ()
local m2 = mariner.new ()
m1:sethp (100)
m1:heal (13)
m2:sethp (90)
m2:heal (5)
print ("Mariner 1 has got "..m1.hp.." hit points")
print ("Mariner 2 has got "..m2.hp.." hit points")
```

And the output:

```Mariner 1 has got 113 hit points
Mariner 2 has got 95 hit points
```

We actually use the colon here to pass the object ('self' table) to function. But do we have to?

## Simple case

We can get quite the same functionality in different manner:

```mariner = {}

function mariner.new ()
local self = {}

local maxhp = 200
local hp = maxhp

function self.heal (deltahp)
hp = math.min (maxhp, hp + deltahp)
end
function self.sethp (newhp)
hp = math.min (maxhp, newhp)
end
function self.gethp ()
return hp
end

return self
end

-- Application:
local m1 = mariner.new ()
local m2 = mariner.new ()
m1.sethp (100)
m1.heal (13)
m2.sethp (90)
m2.heal (5)
print ("Mariner 1 has got "..m1.gethp ().." hit points")
print ("Mariner 2 has got "..m2.gethp ().." hit points")
```

Here we've got not only variables `maxhp` and `hp` encapsulated, but also reference to `self` (note `function self.heal` instead of `function self:heal` - no more `self` sugar). This forks because each time `mariner.new ()` is invoked new independent closure is constructed. It is hard not to notice the performance improvement in all methods except access to private variables `hp` (`self.hp` in first case is faster then `self.gethp ()` in second). But lets see the next example.

## Complex case

```--------------------
-- 'mariner module':
--------------------
mariner = {}

-- Global private variables:
local idcounter = 0
local defaultmaxhp = 200
local defaultshield = 10

-- Global private methods
local function printhi ()
print ("HI")
end

function mariner.setdefaultmaxhp (value)
defaultmaxhp = value
end

-- Global public variables:
mariner.defaultarmorclass = 0

function mariner.new ()
local self = {}

-- Private variables:
local maxhp = defaultmaxhp
local hp = maxhp
local armor
local armorclass = mariner.defaultarmorclass
local shield = defaultshield

-- Public variables:
self.id = idcounter
idcounter = idcounter + 1

-- Private methods:
local function updatearmor ()
armor = armorclass*5 + shield*13
end

-- Public methods:
function self.heal (deltahp)
hp = math.min (maxhp, hp + deltahp)
end
function self.sethp (newhp)
hp = math.min (maxhp, newhp)
end
function self.gethp ()
return hp
end
function self.setarmorclass (value)
armorclass = value
updatearmor ()
end
function self.setshield (value)
shield = value
updatearmor ()
end
function self.dumpstate ()
return string.format ("maxhp = %d\nhp = %d\narmor = %d\narmorclass = %d\nshield = %d\n",
maxhp, hp, armor, armorclass, shield)
end

-- Apply some private methods
updatearmor ()

return self
end

-----------------------------
-- 'infested_mariner' module:
-----------------------------

-- Polymorphism sample

infested_mariner = {}

function infested_mariner.bless (self)
-- No need for 'local self = self' stuff :)

-- New private variables:
local explosion_damage = 700

-- New methods:
function self.set_explosion_damage (value)
explosion_damage = value
end
function self.explode ()
print ("EXPLODE for "..explosion_damage.." damage!!\n")
end

-- Some inheritance:
local mariner_dumpstate = self.dumpstate -- Save parent function (not polluting global 'self' space)
function self.dumpstate ()
return mariner_dumpstate ()..string.format ("explosion_damage = %d\n", explosion_damage)
end

return self
end

function infested_mariner.new ()
return infested_mariner.bless (mariner.new ())
end

---------------
-- Application:
---------------
local function printstate (m)
print ("Mariner [ID: '"..m.id.."']:")
print (m.dumpstate ())
end

local m1 = mariner.new ()
local m2 = mariner.new ()
m1.sethp (100)
m1.heal (13)
m2.sethp (90)
m2.heal (5)
printstate (m1)
printstate (m2)
mariner.setdefaultmaxhp (400) -- We've got some upgrades here
local m3 = mariner.new ()
printstate (m3)

local im1 = infested_mariner.new ()
local im2 = infested_mariner.bless (m1)

printstate (im1)
printstate (im2)

im2.explode ()
```

The output:

```Mariner [ID: '0']:
maxhp = 200
hp = 113
armor = 130
armorclass = 0
shield = 10

Mariner [ID: '1']:
maxhp = 200
hp = 95
armor = 130
armorclass = 0
shield = 10

Mariner [ID: '2']:
maxhp = 400
hp = 400
armor = 130
armorclass = 0
shield = 10

Mariner [ID: '3']:
maxhp = 400
hp = 400
armor = 130
armorclass = 0
shield = 10
explosion_damage = 700

Mariner [ID: '0']:
maxhp = 200
hp = 113
armor = 130
armorclass = 0
shield = 10
explosion_damage = 700

EXPLODE for 700 damage!!
```

It's all quite self-explained. We've got all the common OOP tricks in pretty clean and fast manner.

## Gain or loose?

Time for battle. The arena is 'Intel(R) Core(TM)2 Duo CPU T5550 @ 1.83GHz'. The competitors are:

```-- Table approach

--------------------
-- 'mariner module':
--------------------
mariner = {}

-- Global private variables:
local idcounter = 0
local defaultmaxhp = 200
local defaultshield = 10

-- Global private methods
local function printhi ()
print ("HI")
end

function mariner.setdefaultmaxhp (value)
defaultmaxhp = value
end

-- Global public variables:
mariner.defaultarmorclass = 0

local function mariner_updatearmor (self)
self.armor = self.armorclass*5 + self.shield*13
end
local function mariner_heal (self, deltahp)
self.hp = math.min (self.maxhp, self.hp + deltahp)
end
local function mariner_sethp (self, newhp)
self.hp = math.min (self.maxhp, newhp)
end
local function mariner_setarmorclass (self, value)
self.armorclanss = value
self:updatearmor ()
end
local function mariner_setshield (self, value)
self.shield = value
self:updatearmor ()
end
local function mariner_dumpstate (self)
return string.format ("maxhp = %d\nhp = %d\narmor = %d\narmorclass = %d\nshield = %d\n",
self.maxhp, self.hp, self.armor, self.armorclass, self.shield)
end

function mariner.new ()
local self = {
id = idcounter,
maxhp = defaultmaxhp,
armorclass = mariner.defaultarmorclass,
shield = defaultshield,
updatearmor = mariner_updatearmor,
heal = mariner_heal,
sethp = mariner_sethp,
setarmorclass = mariner_setarmorclass,
setshield = mariner_setshield,
dumpstate = mariner_dumpstate,
}
self.hp = self.maxhp

idcounter = idcounter + 1

self:updatearmor ()

return self
end

-----------------------------
-- 'infested_mariner' module:
-----------------------------

-- Polymorphism sample

infested_mariner = {}

local function infested_mariner_set_explosion_damage (self, value)
self.explosion_damage = value
end
local function infested_mariner_explode (self)
print ("EXPLODE for "..self.explosion_damage.." damage!!\n")
end
local function infested_mariner_dumpstate (self)
return self:mariner_dumpstate ()..string.format ("explosion_damage = %d\n", self.explosion_damage)
end

function infested_mariner.bless (self)
self.explosion_damage = 700
self.set_explosion_damage = infested_mariner_set_explosion_damage
self.explode = infested_mariner_explode

-- Uggly stuff:
self.mariner_dumpstate = self.dumpstate
self.dumpstate = infested_mariner_dumpstate

return self
end

function infested_mariner.new ()
return infested_mariner.bless (mariner.new ())
end
```

and

```-- Closure approach

--------------------
-- 'mariner module':
--------------------
mariner = {}

-- Global private variables:
local idcounter = 0
local defaultmaxhp = 200
local defaultshield = 10

-- Global private methods
local function printhi ()
print ("HI")
end

function mariner.setdefaultmaxhp (value)
defaultmaxhp = value
end

-- Global public variables:
mariner.defaultarmorclass = 0

function mariner.new ()
local self = {}

-- Private variables:
local maxhp = defaultmaxhp
local hp = maxhp
local armor
local armorclass = mariner.defaultarmorclass
local shield = defaultshield

-- Public variables:
self.id = idcounter
idcounter = idcounter + 1

-- Private methods:
local function updatearmor ()
armor = armorclass*5 + shield*13
end

-- Public methods:
function self.heal (deltahp)
hp = math.min (maxhp, hp + deltahp)
end
function self.sethp (newhp)
hp = math.min (maxhp, newhp)
end
function self.gethp ()
return hp
end
function self.setarmorclass (value)
armorclass = value
updatearmor ()
end
function self.setshield (value)
shield = value
updatearmor ()
end
function self.dumpstate ()
return string.format ("maxhp = %d\nhp = %d\narmor = %d\narmorclass = %d\nshield = %d\n",
maxhp, hp, armor, armorclass, shield)
end

-- Apply some private methods
updatearmor ()

return self
end

-----------------------------
-- 'infested_mariner' module:
-----------------------------

-- Polymorphism sample

infested_mariner = {}

function infested_mariner.bless (self)
-- No need for 'local self = self' stuff :)

-- New private variables:
local explosion_damage = 700

-- New methods:
function self.set_explosion_damage (value)
explosion_damage = value
end
function self.explode ()
print ("EXPLODE for "..explosion_damage.." damage!!\n")
end

-- Some inheritance:
local mariner_dumpstate = self.dumpstate -- Save parent function (not polluting global 'self' space)
function self.dumpstate ()
return mariner_dumpstate ()..string.format ("explosion_damage = %d\n", explosion_damage)
end

return self
end

function infested_mariner.new ()
return infested_mariner.bless (mariner.new ())
end
```

Speed test code for table approach:

```assert (loadfile ("tables.lua")) ()

local mariners = {}

local m = mariner.new ()

for i = 1, 1000000 do
for j = 1, 50 do
-- Poor mariner...
m:sethp (100)
m:heal (13)
end
end
```

Speed test code for closures approach:

```assert (loadfile ("closures.lua")) ()

local mariners = {}

local m = mariner.new ()

for i = 1, 1000000 do
for j = 1, 50 do
-- Poor mariner...
m.sethp (100)
m.heal (13)
end
end
```

The result:

```tables:
real    0m47.164s
user    0m46.944s
sys     0m0.006s

closures:
real    0m38.163s
user    0m38.132s
sys     0m0.007s
```

Memory usage test code for table approach:

```assert (loadfile ("tables.lua")) ()

local mariners = {}

for i = 1, 100000 do
mariners[i] = mariner.new ()
end

print ("Memory in use: "..collectgarbage ("count").." Kbytes")
```

Memory usage test code for closures approach:

```assert (loadfile ("closures.lua")) ()

local mariners = {}

for i = 1, 100000 do
mariners[i] = mariner.new ()
end

print ("Memory in use: "..collectgarbage ("count").." Kbytes")
```

The result:

```tables:
Memory in use: 48433.325195312 Kbytes

closures:
Memory in use: 60932.615234375 Kbytes
```

No winners, no loosers. Let's see what we've got here after all...

## Outro

```+---------------------------------------+---------------------------+-------------------------------------------------+
| Subject                               | Tables approach           | Closured approach                               |
+---------------------------------------+---------------------------+-------------------------------------------------+
| Speed test results                    | 47 sec.                   | 38 sec.                                         |
| Memory usage test results             | 48433 Kbytes              | 60932 Kbytes                                    |
| Methods declaration form              | Messy                     | More clean                                      |
| Private methods                       | Fine                      | Fine                                            |
| Public methods                        | Fine                      | Fine                                            |
| Private variables                     | Not available             | Fine                                            |
| Public variables                      | Fine                      | Fine                                            |
| Polymorphism                          | Fine                      | Fine                                            |
| Function overriding                   | Ugly (namespace flooding) | Fine (if we grant access only to direct parent) |
| Whole class definition (at my taste)  | Pretty messy              | Kinda clean                                     |
+---------------------------------------+---------------------------+-------------------------------------------------+
```

As you can see, both approaches are pretty similar by functionality but have significant differences by representation. The choice of approach mostly depends on aesthetic preferences of programmer. I personally would prefer to use closure approach for big objects and tables with data only (no function references) for small things. BTW, don't forget about metatables.