So, I have this lua class (really a metatable) that is getting overwritten by one of it's children. Here is the code that makes the class:
--// Class
local Lexer = {
Text = "",
Pos = nil,
CC = nil
}
--// Initializer
function Lexer.new(Text, Fn)
-- Set metatable
self = setmetatable({}, Lexer)
-- Set variables
self.Text = Text
self.Pos = POS.new(0, 0, 0, Fn, Text)
self.CC = nil
self:Advance()
-- Return
return self
end
And here is the code for the POS module, which I am including:
--// Make the module
local Position = {
Idx = 0,
Line = 0,
Col = 0,
Fn = "",
Ftxt = ""
}
--// Constructor
function Position.new(Idx, Line, Col, Fn, Ftxt)
-- Set metatable
self = setmetatable({}, Position)
-- Set variables
self.Idx = Idx
self.Line = Line
self.Col = Col
self.Fn = Fn
self.Ftxt = Ftxt
-- Return self
return self
end
I have a .__index method in both of them. Help is appreciated!
Oh, and, POS is defined like:
local POS = require("lib/position")
self is not defined and therefore you use the global self as a variable. Since you call the constructor of Pos while initializing Lexer it will cause errors. Prefix both self with local.
self is only automatically defined if using the : syntax, e.g. Lexer:new() and function Lexer:new(Text, Fn).
Related
How to inherit a new class player from class actor and make method actor:new(x, y, s) called in method player:new(x, y, s) with the same parameters. I need to make player:new the same but with additional parameters so the player can have more properties than actor.
Is there a way to do this not only in new method, but in other methods, like player:move(x, y) will call actor:move(x, y) or self:move(x, y) but with additional code?
I use this pattern to make classes in modules:
local actor = {}
function actor:new(x, y, s)
self.__index = self
return setmetatable({
posx = x,
posy = y,
sprite = s
}, self)
end
-- methods
return actor
A good way to do this is to have a separate function that initializes your instance. Then you can simply call the base classes initialization within the inherited class.
Like in this example: http://lua-users.org/wiki/ObjectOrientationTutorial
function CreateClass(...)
-- "cls" is the new class
local cls, bases = {}, {...}
-- copy base class contents into the new class
for i, base in ipairs(bases) do
for k, v in pairs(base) do
cls[k] = v
end
end
-- set the class's __index, and start filling an "is_a" table that contains this class and all of its bases
-- so you can do an "instance of" check using my_instance.is_a[MyClass]
cls.__index, cls.is_a = cls, {[cls] = true}
for i, base in ipairs(bases) do
for c in pairs(base.is_a) do
cls.is_a[c] = true
end
cls.is_a[base] = true
end
-- the class's __call metamethod
setmetatable(cls, {__call = function (c, ...)
local instance = setmetatable({}, c)
-- run the init method if it's there
local init = instance._init
if init then init(instance, ...) end
return instance
end})
-- return the new class table, that's ready to fill with methods
return cls
end
You would simply do:
actor = CreateClass()
function actor:_init(x,y,s)
self.posx = x
self.posy = y
self.sprite = s
end
player = CreateClass(actor)
function player:_init(x,y,s,name)
actor.init(self, x,y,s)
self.name = name or "John Doe"
end
I'm learning how to use Lua and Love2d and I want to create a Vec2 class using metamethods and metatables. This is what I have so far:
class.lua: (The base class files)
local Class = {}
Class.__index = Class
-- Constructor
function Class:new() end
-- Inherite from Class
-- type = The name of the new class
function Class:derive(type)
print("Class:", self)
local cls = {}
cls["__call"] = Class.__call
cls.type = type
cls.__index = cls
cls.super = self
setmetatable(cls, self)
return cls
end
function Class:__call(...)
local inst = setmetatable({}, self)
inst:new(...)
return inst
end
function Class:getType()
return self.type
end
return Class
vec2.lua
local class = require "class"
local Vec2 = class:derive("Vec2")
function Vec2:new(x, y)
self.x = x or 0
self.y = y or 0
getmetatable(self).__add = Vec2.add
end
function Vec2.add(a, b)
local nx, ny
nx = a.x + b.x
ny = a.y + b.y
return Vec2:new(nx, ny)
end
return Vec2
and in my main.lua I have:
local v1 = Vec2:new(10, 10)
local v2 = Vec2:new(5, 3)
local v3 = v1 + v2
print("v3:", v3.x, v3.y)
and I get this error:
Error: main.lua:12: attempt to perform arithmetic on local 'v1' (a nil
value)
Vec2.new does not return a value. Hence the assignment local v1 = Vec2:new(10,10) results in v1 being nil
Try local v1 = Vec2(10,10) instead. Same mistake in Vec2.add
The instance is created in the __call metamethod which calls new with your parameters. You're not supposed to call new directly unless you want to re-initialize an existing instance.
function Class:__call(...)
local inst = setmetatable({}, self)
inst:new(...)
return inst
end
I want to build a simple inheritance hierarchy in Lua. The BaseClass has two attributes, a single value val and a table vals. If I create two objects foo and bar of the SubClass and change these two attributes, changes of val work as expected, but for vals it seems like both objects share the same table internally.
BaseClass = {}
function BaseClass:new()
o = {}
setmetatable(o, self)
self.__index = self
o.val = 0
o.vals = {}
return o
end
SubClass = BaseClass:new()
function SubClass:new()
o = {}
setmetatable(o, self)
self.__index = self
return o
end
foo = SubClass:new()
bar = SubClass:new()
foo.val = 1
bar.val = 2
foo.vals[#foo.vals + 1] = 1
bar.vals[#bar.vals + 1] = 2
print(foo.val, bar.val)
print(#foo.vals, #bar.vals)
The code prints
1 2
2 2
How can I solve this? How do I create two different tables for foo and bar?
Your new method does not distinguish between subclasses and instances. (I don't know why Programming in Lua does it this way.) One way to solve this is to have a separate method to make subclasses:
BaseClass = {}
BaseClass.__index = BaseClass
function BaseClass:new()
o = {}
setmetatable(o, self)
o.val = 0
o.vals = {}
return o
end
function BaseClass:subclass()
local c = {}
setmetatable(c, self)
c.__index = c
return c
end
SubClass = BaseClass:subclass()
I need helps on writing OOP on LUA. I am following this tutorial. However, I have no idea on how to call superclass constructor.
-- Base class
setmetatable(BaseClass, {
__call = function (cls, ...)
local self = setmetatable({}, cls)
self._value = '12345'
return self
end,
})
-- Derived Class
setmetatable(DerivedClass, {
__index = BaseClass, -- this is what makes the inheritance work
__call = function (cls, ...)
local self = ???
-- How to call superclass constructor here?
return self
end,
})
function DerivedClass:haha()
print(self._value)
self._value = 0 -- Works on _value for example
print(self._value)
end
-- Create instance
instance = DerivedClass()
assert_not_nil(instance._value) -- instance._value always nil here...
instance:haha() -- print 12345 and print 0
I have tried following
local self = setmetatable({}, BaseClass) or local self = setmetatable({}, BaseClass())
None of them works.
Furthermore, what is the arguments cls refer to on __call if I execute code DerivedClass() ?
Thanks
I want to create a subclass, ess say, to the built-in ss class. I'd like to be able to convert an existing ss object to an ess object and at the same time add the missing properties, e.g. w, by something like this
sys=ss(a,b,c,d);
esys=ess(sys,w);
but I can't figure out how to setup the constructor correctly. What is the best way to achieve this? My code currently looks like this
classdef ess < ss
properties
w
end
methods
function obj = ess(varargin)
if nargin>0 && isa(varargin{1},'StateSpaceModel')
super_args{1} = sys;
else
super_args = varargin;
end
obj = obj#ss(super_args{:});
end
end
end
But this does not work as I get the following error:
>> ess(ss(a,b,c,d))
??? When constructing an instance of class 'ess', the constructor must preserve
the class of the returned object.
Of course I could copy all the object properties by hand but it seems to me that there should be some better way.
Here is an example of what I had in mind:
classdef ss < handle
properties
a
b
end
methods
function obj = ss(varargin)
args = {0 0}; %# default values
if nargin > 0, args = varargin; end
obj.a = args{1};
obj.b = args{2};
end
end
end
and:
classdef ess < ss
properties
c
end
methods
function obj = ess(c, varargin)
args = {};
if nargin>1 && isa(varargin{1}, 'ss')
args = getProps(varargin{1});
end
obj#ss(args{:}); %# call base-class constructor
obj.c = c;
end
end
end
%# private function that extracts object properties
function props = getProps(ssObj)
props{1} = ssObj.a;
props{2} = ssObj.b;
end
Lets test those classes:
x = ss(1,2);
xx = ess(3,x)
I get:
xx =
ess handle
Properties:
c: 3
a: 1
b: 2
Methods, Events, Superclasses