kikito / middleclass Goto Github PK
View Code? Open in Web Editor NEWObject-orientation for Lua
Home Page: https://github.com/kikito/middleclass
License: MIT License
Object-orientation for Lua
Home Page: https://github.com/kikito/middleclass
License: MIT License
I think that not having the _classes variable local allows for more extension to MiddleClass. For example, we could replicate this line here:
assert(_classes[theClass]~=nil, "Use Class:new instead of Class.new")
One way to do this might be by putting it in Object.classes or Object._classes or something like that.
On wiki it's said that the full list of supported methamethods are: '__add', '__call', '__concat', '__div', '__le', '__lt', '__mod', '__mul', '__pow', '__sub', '__tostring', '__unm'
whereas I've had success with __eq
as well. Is this info dated or was it not supposed to work?
Thanks
The date in middleclass.lua: is it meant to be 19 Oct 2009? Are you keeping it as the first release date or something?
I find it a little confusing because it says "MiddleClass - v1.4" (or something similar), and then, after your name, it gives the 19 Oct 2009 (which 1.4 obviously wasn't released).
If I declare __newindex
, I can't create public attributes in initialize
because __newindex
is being called. Is this intentional?
class = 'middleclass.lua'
local MyClass = class('MyClass')
function MyClass:initialize(x)
self.x = x
--print("X = " .. self.x) --> error
end
local _table = {}
function MyClass:__newindex(key, value)
_table[key] = value
print("Key: " .. key .. " Value: " .. value)
end
local myInstance = MyClass:new(1)
myInstance.x = 2
print(myInstance.x)
Output:
Key: x Value: 1
Key: x Value: 2
nil
I'd love to be able to write an __index function for classes, and it would be called when the requested instance method can't be found in the subclass.
Here is my original script. It works fine without OOP:
local t = {
pos = {2, 4},
size = {8, 16}
}
setmetatable(t, {
__index = function(table, key)
if key == "x" then return table.pos[1]
elseif key == "y" then return table.pos[2]
elseif key == "w" then return table.size[1]
elseif key == "h" then return table.size[2]
end
end,
__newindex = function(table, key, value)
if key == "x" then table.pos[1] = value
elseif key == "y" then table.pos[2] = value
elseif key == "w" then table.size[1] = value
elseif key == "h" then table.size[2] = value
end
end
})
print(t.x) -- 2
t.x = 222
print(t.pos[1]) -- 222
But with middleclass it doesn't work:
local class = require "middleclass"
local T = class("T")
function T:__index(key)
if key == "x" then return self.pos[1]
elseif key == "y" then return self.pos[2]
elseif key == "w" then return self.size[1]
elseif key == "h" then return self.size[2]
end
end
function T:__newindex(key, value)
if key == "x" then self.pos[1] = value
elseif key == "y" then self.pos[2] = value
elseif key == "w" then self.size[1] = value
elseif key == "h" then self.size[2] = value
end
end
function T:initialize()
self.pos = {2, 4}
self.size = {6, 8}
end
local t = T:new()
print(t.x) -- nil
t.x = 222
print(t.pos[1]) -- attempt to index a nil value (field 'pos')
Some of the code in the examples of mixins is wrong.
HasWings = { -- HasWings is a module, not a class. It can be "included" into classes
fly = function ()
print('flap flap flap I am a ' .. self.class.name)
end
}
Where is self coming from? It should be:
function(self)
And then this:
DrinksCoffee = {
included = function(class, coffeeTime) {
print(class.name .. ' drinks coffee at ' .. coffeeTime)
class.coffeeTime = coffeeTime
}
}
Lua won't accept braces for functions. Also the function definition should include self:
function(self, class, coffeeTime)
That's all I could find. :)
Hi,
I am trying to use your class, and looking at the example given at
https://github.com/kikito/middleclass/wiki/Quick-Example
I want to actually have the Person class in a different file and the AgedPerson in a different file.. and then have a main lua file that creates the classes?
How do you do that?
In some occasions it is desirable to split object creation into two steps: the "allocation" step and the "initialization" step. This way mixins can modify instances before initialize is called.
(reference: https://github.com/kikito/middleclass-extras/issues/#issue/4 )
I just stumbled across the issue given in the title.
I knew from the documentation that for each class a static variable name
is defined but I wouldn't have guessed (and find it quite restricting) that this affects the namesapce of instance methods. Don't Class.sth
and instance.sth
have different look-up chains?
Consider the following code sample.
local class = require 'middleclass'
local Foo = class 'Foo'
local foo = Foo()
print(Foo.name) --> Foo
assert(foo.class.name == Foo.name) -- secure fallback to get static class members
print(foo.name) --> nil
-- Foo.static.name = 'Bar' -- has no effect
function Foo:name() -- equivalent to function Foo.name(self)
print('method "name" is called')
end
-- foo:name() -- attempt to call a nil value (method 'name')
print(Foo.name) --> function: 0x123456
print(foo.name) --> nil
Is this a bug, intended, unavoidable? What could be a workaround if one really wanted a name
method? (I know that using getName
would be one solution.)
Hello! I inspected your code and its behavior in lovebird. I created a chain of classes, inherited from each other, watched in their subclasses
fields and all these fields are empty! Maybe I don't get something but I think there is a bug:
Line 154 in 6102f67
self.subclasses[name] = subclass
Also I can be wrong, but I feel that for loop in _propagateInstanceMethod
at lines 53
-58
does nothing useful.
Lines 53 to 57 in 6102f67
Thank you for this fantastic library!
local class = require "lua-resque.deps.middleclass"
local redis = require 'redis'
local Resque_Redis = class('Resque_Redis')
function Resque_Redis:initialize(sredisServer, sredisDatabase)
local client = redis.connect('127.0.0.1', 6379)
self.client = client
return client
end
function Resque_Redis.__call(m)
self.client[m]("q")
end
return Resque_Redis
Trying to use it:
local r = Resque_Redis:new()
r:sadd('queues', queue)
attempt to call method 'sadd' (a nil value)
Title says it all.
I recently ran into this problem, caused by a messy series of require()
calls on my part:
local class = require("middleclass")
local Foo = class("Foo", Bar)
The problem was that the game had not yet created the Bar
class due to my mismanagement of the require()
order. Middleclass silently went on with this, making Object
the parent of Foo
instead. This caused some bugs that, admittedly, were not difficult to track down. But it got me thinking.
I would like to propose a patch where Middleclass will report such code as above is an error. In particular:
local class = require("middleclass")
-- No errors.
local Foo = class("Foo")
-- Also no errors
local Bar = class("Bar", Foo)
-- But this fails with an error because we explicitly provide
-- a parent class which does not exist.
local Baz = class("Baz", NilParentClass)
I would be happy to code a patch and test cases for this if you are interested in having such behavior in the library.
Hi there,
In the documentation, in the quick example we can read:
function Person:speak()
and then
function AgedPerson:speak()
Person.speak(self) -- prints "Hi, I am xx."
How does one go to do the same but with a method that has parameters?
(Aka, if the first function Person:speak()
had a parameter itself) like
function Person:speak(salutation)
I tried
function AgedPerson:speak(salutaion)
Person.speak(self, salutation)
But I didn't get it right.
Is this possible?
Thanks
Hi
i like middleclass but (even as per your advice) i was in the process of shifting over to raw metatables
as far as i can see though, middleclass shouldn't be any slower? is there some performance consideration you made to not include a strategy for properties or was it simply not featured/for cleanliness and purity of code reasons?
i am trying to figure it out, and i am thinking a little bit of the specifics of calling
object.x = 55
this means no self reference is passed unless we had to load all the functions with the references already?
Thanks for your help (and especially inspect ;) )
Using this library for the first time and so far I've found it absolutely wonderful. Great job ๐
I was pleasantly surprised when I've found out that this works:
local SomeClass = class("SomeClass")
local someObj = SomeClass()
I think that this must be documented, because I've found no mentions that you can do this stuff.
Any reason why SomeClass:new()
is used everywhere other than missing mentions of this? Does SomeClass()
have any drawbacks?
I'm not sure if I'm doing something rong or if this actually is a problem.
When I create a class just like you do in the example (class:initialize()) then I only can access the name and super properties if I'm calling myClass.class.name or myClass.class.super. It doesn't work with myClass.name like in the example.
My code is something like this:
`
-- base class
local control = gui.class("base") -- gui.class is just middleclass
function control:initialize(parent)
self.parent = parent
-- self.name is nil here
end
return control
-- label class
local control = gui.class("label", gui.controls.base)
function control:initialize(parent, text)
gui.controls.base.initialize(self,parent)
self.text = text
-- self.name is also nil here
end
return control
-- main file
local screen = gui.controls.screen()
local label = gui.controls.label(screen,"Test Text")
-- label.name and label.super are both nil
-- label.class.name and label.class.super both work
`
I have built a class hierarchy with middleclass and it works magnificently until I try and turn it into a module. I am new to lua but not to oop. Most instructions I find for module creation seem to cause conflicts with my middleclass hierarchy. What is your recommended way of making middleclass based class hierarchies into modules so that huge code projects can be partitioned into modules and included in new code sections?
Hi, what do you think about implementing destructors in middleclass?
That can possibly be done in a way similar to how they are implemented in Klass module - by overriding __gc
metamethod (using newproxy()
trick for Lua 5.1 and without it for 5.2 and above).
In the changelog you say that init.lua has disappeared, yet it is still there. I assume you forgot to remove it, right?
I'd like to loop the children of the Object class so I can execute a function on every one of them.
setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) or super.static[k] end })
if rawget(dict,k) is a boolean value and its value is false, it went wrong.
so you should change the or expression to if/else
Line 118:typeof (aClass.isSubclassof)=="function. Should be self.class .issubclassof
Currently __equal meta method is set in middleclass.
User must implement __eq meta method when they actually needs raw table address compare.
Shall we just leave __eq unset?
First thank you for a pretty robust class library!
I have one helpful feature suggestion for the library that I've used in my projects. The ability to check class names by string without having to require the class object as a dependency. I hope this makes sense?
If I have multiple different classes, and I want or need to use isInstanceOf to check for other classes, I would need to require the classes I'm checking, for every class module. This will unnecessarily bloat the dependencies when all it should need to do is compare against the class name.
Hi,
I want use cjson to serialize a instance of middleclass object but get a error.
Cannot serialise table: table key must be a number or string
Here is the demo code:
local Foo = class("Foo")
local foo = Foo:new()
local cjson = require "cjson"
cjson.encode(foo)
I understand all the lua object is simulated by lua table, so in theory a object should can be convert to a json encoded text.
Would you point out the reason get this error? or give any advice how to bypass this issue?
Thanks
kenshin
could it be bettle if we change
setmetatable(aClass.static, { __index = function(,k) return dict[k] or superStatic[k] end })
to
setmetatable(aClass.static, { __index = function(,k) return rawget(dict,k) or superStatic[k] end })
?
Hi!
It seems this library is unable to make use of new local values and class instance functions during a "recompile". The metatable for the instance is pointing to an already set entry and will not be updated with a fresh compile of a module with "require" or "dofile".
Does anyone have a way to add this support? I'm unable to get this working myself unfortunately
I'm porting PHP web framework to Lua. All is going well except I need something to replace PHP getter __get()
. In previous versions there was Indexable mixin with index()
function, I need same for middleclass 3.x.
Also question about porting, I'm replacing get_class($this)
with self.class.name
, is it proper to get class name in such way? Also question how to call method in parent class, the way present in wiki a bit wierd, if I try self.class.super.method(self, ...)
it gives wrong parent on second level of inheritence, it gives parent of first level. My temporary solution:
local Database_Query_Builder_Select = Database_Query_Builder_Where:subclass('Database_Query_Builder_Select')
local parent = Database_Query_Builder_Where
function Database_Query_Builder_Select:initialize(columns)
...
-- Start the query with no actual SQL statement
parent.initialize(self, Database.SELECT)
end
After using middleclass
for some time I found myself out doing things like this:
local _M = require('middleclass')('State.Moving', require('State.Base'))
:include(require('Mixin.Character'))
:include(require('Mixin.Moving'))
It would be more convenient to be able to do it without constantly calling require
, e.g.:
local _M = require('middleclass')('State.Moving', 'State.Base')
:include('Mixin.Character')
:include('Mixin.Moving')
It's something that e.g. Moose OO framework in Perl does with its extends
and with
keywords.
I also have read a discussion on the similar issue #52, and I think that format of an argument (i.e., string with class name vs class variable) already provides sufficient explicitness, and if in doubt / having issues, it's easy to switch back to class variables instead of strings in some particular project.
Please close if I missed a part of the docs ;)
I'd like to have some information about inheritance in middle class - the lua users wiki (http://lua-users.org/wiki/ObjectOrientedProgramming) says it supports "basic inheritance". If so, how exactly does it work and what are it's limitations?
Wiki homepage says that "The code is reasonably commented", but middleclass.lua doesn't have a single comment. Am I missing something?
The middleclass-extras repo clearly says not to use it anymore but how do we do what Indexable allows you to do in 2.0?
This is a very nice library - thank you for your work!
I noticed that in the library there are four default methods that aren't mentioned in the wiki documentation, namely isInstanceOf
, isSubclassOf
, allocate
and subclassed
. Was there documentation for these that got deleted from the wiki somehow? I see references to isInstanceOf
and isSubclassOf
in UPDATING.md, which makes me suspect that there might have been something there before. In any case, it would be nice to have some documentation and examples for these methods.
Consider the following:
Class B inherits Class A
Class C inherits Class A
Class A implements __lt comparison meta method.
When comparing Class B and Class C the library errors with "Trying to compare two tables"
How to split Game
class to several files?
local class = require("middleclass")
local Game = class("Game")
function Game:main_menu()
end
function Game:options_menu()
end
return Game
Given the file static.lua
:
local class = require("middleclass")
local C = class("C")
function C.static:foo()
return "<static> C.static:foo"
end
function C:initialize()
self.value = self.class:foo()
end
function C:foo()
return "<instance> C:foo"
end
local c = C()
print(("[%s] C.static.foo"):format(C.static.foo))
print(("[%s] C.foo"):format(C.foo))
print(("[%s] c.foo"):format(c.foo))
print(("C:foo() = %q"):format(C:foo()))
print(("c:foo() = %q"):format(c:foo()))
print(("c.value = %q"):format(c.value))
local D = class("D", C)
local d = D()
print("---")
print(("[%s] D.static.foo"):format(D.static.foo))
print(("[%s] D.foo"):format(D.foo))
print(("[%s] d.foo"):format(d.foo))
print(("D:foo() = %q"):format(D:foo()))
print(("d:foo() = %q"):format(d:foo()))
print(("d.value = %q"):format(d.value))
And its output:
> lua static.lua
[function: 0x40cf4998] C.static.foo
[function: 0x40cf4998] C.foo
[function: 0x40cfcf90] c.foo
C:foo() = "<static> C.static:foo"
c:foo() = "<instance> C:foo"
c.value = "<static> C.static:foo"
---
[function: 0x40cfcf90] D.static.foo
[function: 0x40cfcf90] D.foo
[function: 0x40cfcf90] d.foo
D:foo() = "<instance> C:foo"
d:foo() = "<instance> C:foo"
d.value = "<instance> C:foo"
You can see D's static functions addresses all point to C's instance functions and initialization of D's instances calls them, resulting in a wrong d.value
(it should be the same as c.value
: "<static> C.static:foo"
).
Reference: http://love2d.org/forums/viewtopic.php?f=4&t=2278
Hi
Newbie here, I have been experimenting a bit with Lua and the Middleclass library, an apparent memory leak with Middleclass has got me totally stumped. Is this really a leak or am I misunderstanding something.
I cut my code down to just the following lines
Code: Select all
require "middleclass"
local oPlayer = class("A Player") -- This single line is enough to show a leak
collectgarbage("collect")
local endMem = string.format("\nMemory used after Garbage Collect = %.1f kbytes", collectgarbage("count"))
print (endMem)
If I run this code repeatedly from a Lua console with dofile("myTest.lua") I get the following increasing memory usage.
Memory used after Garbage Collect = 43.8 kbytes
Memory used after Garbage Collect = 46.0 kbytes
Memory used after Garbage Collect = 48.2 kbytes
Memory used after Garbage Collect = 50.6 kbytes
If I add the line oPlayer = nil, that makes no difference either.
Sorry if I am getting something wrong, I am new to lua.
I was just trying to use your library and after started to play with the examples of the wiki.
I put the following in a file.
package.path = package.path .. ";../external/middleclass/?.lua"
class = require "middleclass"
Person = class('Person') --this is the same as class('Person', Object) or Object:subclass('Person')
function Person:initialize(name)
self.name = name
end
function Person:speak()
print('Hi, I am ' .. self.name ..'.')
end
but the result is ...
test = Person:new("test")
> test.speak()
/home/karl/tproject/abstract/teobject.lua:10: attempt to index a nil value (local 'self')
stack traceback:
/home/karl/tprojectabstract/teobject.lua:10: in function </home/karl/tproject/abstract/teobject.lua:9>
(...tail calls...)
[C]: in ?
I am using lua 5.3. What do I have to do to get things working?
It would be quite helpful to add a mixins
field to classes, adding mixins to this array when include
is called, and an includes
method on class instances that return true if the class of that object includes the specified mixin.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.