rxi / classic Goto Github PK
View Code? Open in Web Editor NEWTiny class module for Lua
License: MIT License
Tiny class module for Lua
License: MIT License
There seems to be a problem with the design of the is
method.
You can't do things like nil:is(SomeType)
This makes it pretty much useless for type checking as you have to guarantee that class variables are never nil.
I tried implementing it as a helper function with a little change...
function is(self, T)
if self == T then
return true
else
local mt = getmetatable(self)
while mt do
if mt == T then
return true
end
mt = getmetatable(mt)
end
end
return false
end
but it has the same problem.
Maybe there is a way to get around it?
This would also effect #20
function Object:as(T)
if self.is(T) then
return self
end
return T
end
Hi.
I am trying to implement multiple inheritance but when I use more than 2 in a chain, I get the following error:
Error: [love "boot.lua"]:48: Failed to initialize filesystem: already initialized
This is how my code looks like:
Car.lua
local Car = Classic:extend()
function Car:new(_wheels)
self.wheels = _wheels
end
return Car
FamilyCar.lua
local Car = require "Car"
local FamilyCar = Car:extend()
function FamilyCar:new(_seats, _wheels)
self.super.new(self, _wheels)
self.seats = _seats
end
return FamilyCar
SportCar.lua
local FamilyCar = require "FamilyCar"
local SportCar = FamilyCar:extend()
function SportCar:new(_engine, _seats, _wheels)
self.super.new(self, _seats, _wheels)
self.engine = _engine
end
return SportCar
main.lua
Classic = require "classic"
local FamilyCar = require "FamilyCar"
local SportCar = require "SportCar"
peugeot = FamilyCar(4,4)
ferrari = SportCar("V8", 2, 4) --this is causing the error
function love.draw()
love.graphics.print(peugeot.wheels)
end
Here is a project that reproduce the problem:
classictest.zip
I am uncertain if is it a bug, limitation or something I am doing wrong.
I would appreciate any help.
Using:
LOVE 11.4
classic.lua
macOS 12.3.1
Thank you.
Hi, I think that mixins are also useful for acting as a sub-class that can be shared between multiple classes instead of making another base class. With that level of abstraction, i think that implemented mixins should have their own container.
Here's a snippet:
local Human = classic:extend()
local Power = classic:extend()
function Power:magic() end
Human:implement(Power)
function Human:cast()
--instead of
Human:magic()
--i suggest:
Human.Power:magic()
end
Also, Power class should have it's own self
table.
To access the Human class from Power: self.parent.human_name
For clarification: If you have a class Point (like the example in the docs), and then want to create a new Point which is correctly done so: local p = Point(3,4)
But if you instead do: local p = Point:new(3,4)
it just does nothing.
Maybe it's just me who ran into this, but the mistake was not very obvious. Raising an error as hint would be nice, or allowing it as kind of alternative syntax. Whichever is easier, I guess.
Consider hiding the meta methods.
Maybe something like this..
local Object = {}
local Meta =
{
__call = function(self, ...)
local obj = setmetatable({}, self)
obj:new(...)
return obj
end,
__tostring = function(self)
return "Object"
end,
__index = Object
}
setmetatable(Object, Meta)
This can be better explained by looking at the following example, where I create three different classes: a base class called BaseClass
, that's being extended by both ClassOne
and ClassTwo
.
Object = require "classic"
-- BaseClass provides a say() method
local BaseClass = Object:extend()
function BaseClass:new(name)
self._name = name
end
function BaseClass:say()
print("Hello " .. self._name)
end
-- ClassOne extends BaseClass
local ClassOne = BaseClass:extend()
function ClassOne:new()
ClassOne.super:new("Mark")
end
-- ClassTwo extends BaseClass
local ClassTwo = BaseClass:extend()
function ClassTwo:new()
ClassTwo.super:new("John")
end
-- ===================================
-- = Let's try it out: =
-- ===================================
local class_one = ClassOne()
local class_two = ClassTwo()
class_one:say()
class_two:say()
This doesn't work, instead of printing
Hello Mark
Hello John
it prints:
Hello John
Hello John
It seems like the initialization of ClassTwo()
overwrites the _name
variable in ClassOne()
.
Why is this happening?
Can you support getter and setter properties by appending get-
or set-
at the beginning of a function?
-- https://github.com/kikito/middleclass
local middleclass = require "middleclass"
local CreatureMC = middleclass("CreatureMC")
function CreatureMC:__call() print("CreatureMC was called!") end
local AnimalMC = CreatureMC:subclass("AnimalMC")
local CatMC = AnimalMC:subclass("CatMC")
local tomMC = CatMC()
print(tomMC) -- instance of class CatMC
print(pcall(tomMC)) -- called, no errors
-- https://github.com/rxi/classic
local classic = require "classic"
local CreatureCL = classic:extend()
function CreatureCL:__call() print("CreatureCL was called!") end
local AnimalCL = CreatureCL:extend()
local CatCL = AnimalCL:extend()
local tomCL = CatCL()
print(tomCL) -- nil !?
print(pcall(tomCL)) -- called, error (attempt to call a nil value)
-- https://github.com/limadm/lua-oo
local oo = require "oo"
local CreatureOO = oo()
function CreatureOO:__call() print("CreatureOO was called!") end
local AnimalOO = CreatureOO:extend()
local CatOO = AnimalOO:extend()
local tomOO = CatOO()
print(tomOO) -- table
print(pcall(tomOO)) -- error (attempt to call a table value)
Here is the difference between classic and middleclass:
local MiddleClass = require "middleclass"
local M = MiddleClass("M")
function M:initialize()
self.pos = {2, 4}
self.size = {6, 8}
end
function M:__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]
else rawget(self, key)
end
end
function M:__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
else rawset(self, key, value)
end
end
local m = M()
assert(m.x == 2)
m.x = 222
assert(m.pos[1] == 222)
print("No errors in MiddleClass.")
local Classic = require "classic"
local C = Classic:extend()
function C:new()
self.pos = {2, 4}
self.size = {6, 8}
end
function C:__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]
else rawget(self, key)
end
end
function C:__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
else rawset(self, key, value)
end
end
local c = C()
assert(c.x == 2)
c.x = 222
assert(c.pos[1] == 222)
print("No errors in Classic.")
No errors in MiddleClass.
luajit: ../lib/classic.lua:58: attempt to call method 'new' (a nil value)
Hello. I want to extend existing method when extending a class (just add a new function to it, not owerwrite), but don't know how to do it. Here is an example:
local Object = require "classic"
local A = Object:extend()
function A:new()
function self.sayHi()
print("Hi from A!")
end
end
local B = A:extend()
function B:new()
B.super.new(self)
function self.sayHi()
-- B.super.sayHi() -- not working
print("Hi from B!") -- overwrites
end
end
local b = B()
b.sayHi() -- Hi from B only!
local a=classic:extend()
function a:new()
self.foo=1
end
local b=a:extend()
function b:new()
self.super.new(self)
self.bar="hello"
end
local c=b:extend()
function c:new()
self.super.new(self) --Causes endless recursion
end
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.