|
|
#1 |
|
Full Member
Join Date: Mar 2007
Posts: 224
|
LibOOP is a small, framework-independent library that provides easy-to-use object orientation in Lua. If you're still using AceOO-2, or if you've been rolling your own metatables to achieve object orientation, give LibOOP a try.
Main Page: http://www.wowace.com/projects/liboop Getting Started: http://www.wowace.com/projects/liboo...etting-started API: http://www.wowace.com/projects/liboop/pages/api Please leave any feedback in this thread, or file tickets on the project page. Last edited by taleden; 01-31-2009 at 10:57 PM. Reason: 1.0.0-beta |
|
|
|
|
|
#2 |
|
Amazing Member
Join Date: Dec 2006
Location: Lyon, France
Posts: 1,718
|
Some methods almost have the same name, e.g. extend() and extends(), that may be very confusing. I am not a fan of mixing upper and lower case method names too.
Then you have to add some code to have your library properly upgrading. ATM if a newer version of the library is loaded, all old classes are lost. That is not hard though, e.g. for ooSuper, replace: Code:
local ooSuper = setmetatable({}, weakKeys)
Code:
if not LibOOP.ooSuper then
LibOOP.ooSuper = setmetatable({}, weakKeys)
end
local ooSuper = LibOOP.ooSuper
__________________
Author of Squire, Inline Aura and several other addons. If you have a problem and you think the solution involves using a regular expression, then you have two problems. |
|
|
|
|
|
#3 | ||
|
Full Member
Join Date: Mar 2007
Posts: 224
|
Quote:
The case difference came from not wanting to have exactly the same names for the library-wrapped functions and the class/object-inherited-methods, since they take slightly different arguments. Maybe case consistency would be better, it just seemed convenient to me to have an easy distinction between the versions that require you explicitly pass the class/object, and the versions you call directly on the class/object. Quote:
But, yeah, that's on the list. |
||
|
|
|
|
|
#4 | |
|
Amazing Member
Join Date: Dec 2006
Location: Lyon, France
Posts: 1,718
|
Quote:
Thus I would go with something like this: LibOOP:Class(super) or super:extend() => LibOOP:NewClass(super) or super:NewClass() LibOOP:Extends(class, super, direct) or class:extends(super, direct) => LibOOP:IsSubClassOf(class, super, direct) or class:IsSubClassOf(super, direct) LibOOP:New(class, ...) or class:new(...) or class(...) => LibOOP:New(class, ...) or class:New(...) or class(...) LibOOP:GetSuperClass(class) or class:superclass() => LibOOP:GetSuperClass(class) or class:GetSuperClass() etc. Hrm. Actually you do not need to reference the LibOOP itself, so you could ultimately have this: LibOOP:GetSuperClass(class) or class:superclass() => LibOOP.GetSuperClass(class) or class:GetSuperClass() This way you could use the very same function in LibOOP and class, e.g. : Code:
local function class_GetSuperClass(self) -- return the superclass of self end baseClass.GetSuperClass = GetSuperClass LibOOP.GetSuperClass = GetSuperClass
__________________
Author of Squire, Inline Aura and several other addons. If you have a problem and you think the solution involves using a regular expression, then you have two problems. |
|
|
|
|
|
|
#5 | |||
|
Full Member
Join Date: Mar 2007
Posts: 224
|
Quote:
Quote:
Quote:
Actually, in the beginning the only method LibOOP provided was :Class(), because everything else was accessible via the classes/objects themselves. I added the other wrappers later as a safeguard against someone overriding the methods (i.e. if someone overrides :New on their class, then its impossible to instantiate it; if you re-use someone else's code that did this, then what can you do?). On the other hand, maybe that should be allowed. I dunno. Real OO languages don't have this problem of course because all the infrastructure is managed with reserved keywords which can't be overridden in the first place. So maybe the first question is, should LibOOP bother providing these methods at all? Or should it just point out that if you override the provided methods in your class, then you're explicitly disabling portions of the OO functionality. |
|||
|
|
|
|
|
#6 | |
|
Amazing Member
Join Date: Dec 2006
Location: Lyon, France
Posts: 1,718
|
Quote:
__________________
Author of Squire, Inline Aura and several other addons. If you have a problem and you think the solution involves using a regular expression, then you have two problems. |
|
|
|
|
|
|
#7 |
|
Full Member
Join Date: Mar 2007
Posts: 224
|
I had a look at the syntax for a few other popular OO languages, and came up with this:
Code:
CLASS OPERATIONS Ruby PHP Python C++ Java define class class class class class extend class < extends class () class : extends called during extension inherited forbid extension final final is extension forbidden forbid overriding final final test direct extension isassignablefrom test indirect extension kind_of is_subclass_of issubclass isassignablefrom get superclass superclass parent super getsuperclass call inherited method super parent super super OBJECT OPERATIONS Ruby PHP Python C++ Java create from class new new <class>() new new create from object dup clone clone called during creation initialize construct init <class> <class> called during destruction finalizer destruct ~<class> finalize called during cloning initialize_new clone forbid modification freeze is modification forbidden frozen test direct inheritance instance_of test indirect inheritance kind_of instanceof isinstance instanceof get object's class class get_class getclass call inherited method super parent super super I'm also starting to learn toward removing the redundancies in the API, so that the inherited class/object methods are the only way to instantiate/extend/etc. This way, overriding those methods becomes a way of implementing other features, such as giving classes a callback when they're extended, or coding a singleton. On the other hand, things like instanceof and super probably shouldn't be disable-able or override-able. I'm not sure yet whether to try to circumvent that by providing those via the library (instead of via inherited methods), or enforce it by tweaking class/object metatables to forbid redefining those names, or just document that it's not recommended and leave it up to the developer. Comments welcome. |
|
|
|
|
|
#8 |
|
Amazing Member
Join Date: Dec 2006
Location: Lyon, France
Posts: 1,718
|
About instanceof: I think it is better out of the objects and classes. In Java, it is an operator. This allows to accept tests like "null instanceof someClass" or "1 instanceof someClass" without any issue neither error.
About calling overridden methods (super calls): something that should not be forgotten is that when you call overridden method, you do not want the method of the parent class of self but the method of the parent class of the class that defines the method. This is a quite static information. Imagine three classes A, B, C. - B extends A, - C extends A. - A defines the method bark(), - B overrides the method bark() ; the new method calls inherited method bark(). With an instance of C, C.bark() actually is B.bark() that calls A.bark(). If you tried to get super from self, B.bark() would end up calling B.bark() because C inherits from B and you had an infinite recursion loop. Speaking of what, ATM I can cause infinite recursion with current LibOOP with the following code : Code:
local classA = LibOOP:Class()
function classA.prototype:count()
return 1
end
local classB = classA:extend()
function classB.prototype:count()
return self:super("count") + 1
end
local classC = classB:extend()
local obj = classC:new()
print(obj:count()) -- infinite recursion
Code:
function classB.prototype:count() return classA.prototype:count() + 1 end
__________________
Author of Squire, Inline Aura and several other addons. If you have a problem and you think the solution involves using a regular expression, then you have two problems. Last edited by Adirelle; 01-06-2009 at 04:25 PM. |
|
|
|
|
|
#9 | |
|
Full Member
Join Date: Mar 2007
Posts: 224
|
Quote:
However I'm not sure it's really "static" information, because Lua by its nature isn't very static. My hope with LibOOP was to do object orientation in a "Lua-ish" way, preserving as much of Lua's dynamic flavor as is practical. Part of that is the option of changing classes on the fly, and having those changes propagate automatically to subclasses and objects; I think that means the identity of a "super"-called method will have to be evaluated each time. Here's my tentative API for v0.2. The changes are mostly motivated by this discussion, plus the addition of Clone (whose default inherited implementation will function like New followed by a shallow property copy). Code:
define class: LibOOP:Class() extend class: <class>:Extend() overridable get class' parent class: <class>:GetSuperClass() non-overridable // LibOOP:GetSuperClass(ref) test class inheritance: <class>:SubClassOf([class,[ direct]]) non-overridable // LibOOP:SubClassOf(ref[, class[, direct]]) call inherited class method: <class>:Super(method[, ...]) non-overridable create object: <class>:New(...) overridable clone object: <obj>:Clone(...) overridable get object's class: <obj>:GetClass() non-overridable // LibOOP:GetClass(ref) test object inheritance: <obj>:InstanceOf([class[, direct]]) non-overridable // LibOOP:InstanceOf(ref[, class[, direct]]) call inherited object method: <obj>:Super(method[, ...]) non-overridable Last edited by taleden; 01-06-2009 at 05:35 PM. |
|
|
|
|
|
|
#10 |
|
Full Member
Join Date: Mar 2007
Posts: 224
|
I hope to have 0.2-beta ready tonight or tomorrow. The changelog so far is:
Code:
- almost all methods have been renamed for better clarity and consistency - now supports runtime-upgrades via LibStub - the "Super" method of both classes and objects should now work when called via a subclass of the class which defined the method which calls Super() - class methods "GetSuperClass", "SubClassOf" and "Super" (inherited from the base class) may no longer be overridden - object methods "GetClass", "InstanceOf" and "Super" (inherited from the base prototype) may no longer be overridden - constructors are now implemented by overriding the class' "New" method; the object method name "__init" no longer has any special meaning (however, in general, method names beginning with two underscores are still reserved for future magic) - objects now inherit a basic "Clone" method from the base prototype - the library method "Class" no longer accepts an argument; to extend an existing class, use "<class>:Extend()" - the library method "New" is removed; to instantiate a class, use "<class>:New()" or "<class>()" - library methods will accept arguments which are not classes or objects, and will usually return nil or do nothing in this case - messages have been added to errors and assertions to identify what and where the error was - getmetatable() on an object will now return the object's class' prototype table, instead of the class table; it is still not possible to access the real metatables of any LibOOP-managed tables Just now, I was also pondering the scheme for prototyping. In a way, it feels strange to me to just provide a special property on the class table for this purpose; it would be somehow "less obtrusive" to do it some other way, and leave the entire property space free for authors to do as they wish. One thought was for :Class() and :Extend() to have a second return value which would be the prototype table. So, for example, Code:
local MyClass,MyClass_proto = LibOOP:Class() Comments? |
|
|
|
![]() |
«
Previous Thread
|
Next Thread
»
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
|
|
All times are GMT. The time now is 04:13 PM.
WowAce Forums





