Right now I am using closures for implementing OOP in Lua. An abridged example follows. My issue happens when trying to implement stronger_heal
inside infested_mariner
.
--------------------
-- 'mariner module':
--------------------
mariner = {}
-- Global private variables:
local idcounter = 0
local defaultmaxhp = 200
local defaultshield = 10
function mariner.new ()
local self = {}
-- Private variables:
local hp = maxhp
-- Public methods:
function self.sethp (newhp)
hp = math.min (maxhp, newhp)
end
function self.gethp ()
return hp
end
function self.setarmorclass (value)
armorclass = value
updatearmor ()
end
return self
end
-----------------------------
-- 'infested_mariner' module:
-----------------------------
-- Polymorphism sample
infested_mariner = {}
function infested_mariner.bless (self)
-- New methods:
function self.strongerheal (value)
-- how to access hp here?
hp = hp + value*2
end
return self
end
function infested_mariner.new ()
return infested_mariner.bless (mariner.new ())
end
If I place my infested_mariner
definition in another .lua file, it won't be able to access the global private variables, or access to the private variables, defined in the base .lua file. How do I have protected members that only infested_mariner
can access, and the solution doesn't involve having all the derived classes in the same file as the parent?
Note: I am currently using getters and setters in the child class for now.
In Lua, you can only access local variables in their scope. In order to allow other functions to see your variables you will need to rewrite it so the protected variables are in a table that is accessible by the child class.
One way to do this is by just making public properties in the current class and use a naming convention (like names starting with a underscore) to denote the protected stuff. You probably know this but I have to say that I think this approach is usually much simpler to implement than real protected variables.
If you want real protected variables, you need to separate the table for the public and the protected stuff. One approach is to change the bless function so that it receives both these tables:
function infested_mariner.bless (pub, pro)
-- New methods:
function pub.strongerheal (value)
pro.hp = pro.hp + value*2
end
return pub
end
How to set things up so that constructors pass the protected table to each other is left an exercise. If you go this route you probably want to have some function doing it for you so that you don't get a chance to touch the protected table in a day to day basis.
This is a limitation of the closure approach. There is no way to access hp
from outside the closure.
It's kind of an ideology issue... Some people say protected members brake encapsulation, so they should be avoided: Make all data private and expand the interface if need be (add public functions). People who say that tend to like the closure approach.
If you want to use protected members, I would probably not use the closure approach. A good naming convention is probably the easiest thing.
self.public_thing = "asdf"
self._protected_thing = "asdf"
Sure, the data is actually public, but this approach works pretty well. This is pretty much what Python does. It comes in handy when you want to mess with internals, like for testing.