View Full Version : A cleaner/easier class idiom in Lua
Making a class using Lua is pretty gross and requires underlying knowledge about how metatables work and other nonsense. Anyway, I made a function to automate the process.
Example:
Person = class()
function Person:__init(name, age)
self.name = name
self.age = age
end
newPerson = Person("Bob", 41)
Instead of defining a constructor like you normally would, class() creates one for you and then calls __init when the class is created. (Defining __init is optional though.) Also, you now just call the name of the class instead of explicitly calling the constructor, which is how it works in most OO languages. class() also takes an optional argument for a superclass from which to inherit from. (Right now there is not multiple-inheritance because that would take a lot more effort on my part. :))
Here's the definition for class():
function class(superclass, name)
local cls = superclass and superclass() or {}
cls.__name = name or ""
cls.__super = superclass
return setmetatable(cls, {__call = function (c, ...)
self = setmetatable({__class = cls}, cls)
if cls.__init then
cls.__init(self, ...)
end
return self
end})
end
I hope your brain didn't explode.
That's great, a lot easier on the eyes. Hope you don't mind if I steal it! I can make the intro_menu.lua simpler to look at.
That's great, a lot easier on the eyes. Hope you don't mind if I steal it! I can make the intro_menu.lua simpler to look at.
Er, the point of posting it was so anyone could use it. I hereby place it in the public domain.
Also, I can add multiple inheritance and other stuff later. I also made an isinstance() function and an issubclass() function which I'll post later. (I'm not at my own computer at the moment.)
P.S.
Oh, and the name argument is mostly for introspection. (You sadly have to provide it explicitly which violates the DRY principle; there may be a way around this, but I doubt it.) I should probably add a __tostring metamethod to the metaclass (class function) as well for introspective purposes. I guess that would make it a meta-metamethod. Not to be confused with a meta-meta-method. :confused:
function issubclass(class1, class2)
while true do
if class1 == class2 then
return true
end
class2 = class2.__super
if not class2 then
break
end
end
return false
end
function isinstance(inst, cls)
return issubclass(inst.__class, cls)
end
Ok, I tried to convert my classes to use this new and improved system today but ran into a snag.
Everything works fine, but MyObj:FuncName() syntax doesn't work anymore.
Here's a test to illustrate:
//Ian's cool class wrapper to make faking class's easier.
function class(superclass, name)
local cls = {}
cls.__name = name or ""
cls.__super = superclass
return setmetatable(cls, {__call = function (c, ...)
self = setmetatable({__index = cls}, cls)
if cls.__init then
cls.__init(self, ...)
end
return self
end})
end
//here's an example/test using the class function
Monster = class(); //create the class.
//define the class function protypes
function Monster:__init()
//if a function named __init exists, it will be called when an object is initialized (like a constructor)
LogMsg("A monster initted!");
self.hitpoints = 10;
end
function Monster:Hurt(damage)
self.hitpoints = self.hitpoints - damage;
end
//ok, now let's actually make some objects and use them.
dave = Monster();
tom = Monster();
LogMsg("Dave has " .. dave.hitpoints .. " hitpoints.");
LogMsg("Tom has " .. tom.hitpoints .. " hitpoints.");
//dave:Hurt(2); //why can't I do this?
dave.__index.Hurt(dave, 2); //long form
//tom:Hurt(8); //why can't I do this?
tom.__index.Hurt(tom, 8); //long form
//show hitpoints again
LogMsg("Dave has " .. dave.hitpoints .. " hitpoints.");
LogMsg(" Tom has " .. tom.hitpoints .. " hitpoints.");
I want to say dave:Hurt(2) but I have to do dave.__index.Hurt(dave, 2). Any ideas on fixing this? :confused:
function class()
local cls = {}
cls.__index = cls
return setmetatable(cls, {__call = function (c, ...)
instance = setmetatable({}, cls)
if cls.__init then
cls.__init(instance, ...)
end
return instance
end})
end
I stupidly put __index in the wrong table. It works now. (I'm also working on something that will have single, multiple, and diamond inheritance, cooperative methods and other stuff. I have a ton of unit tests this time.)
Thanks, it's working great now.
Powered by vBulletin® Version 4.1.10 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.