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
Related
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).
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 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'm working with objects in octave and I would like to call the superclass set method in the subclass set. In the GNU octave documentation I haven't found how its works so I've tried to use the matlab documentation syntax but I get the next error: '' undefined near line 20 column 5 where the call is.
¿How could I access the superclass method correctly?
Here the code:
function s = set (o, varargin)
s = o;
if (length (varargin) < 2 || rem (length (varargin), 2) != 0)
error ([mfilename " :::: Expecting property/value pairs."]);
endif
while (length (varargin) > 1) #We get the first 2 pairs while exist.
prop = varargin{1};
val = varargin{2};
varargin(1:2) = [];
if (strcmp (prop, "color"))
if (ismember (val, ["black", "red", "green", "yellow", "blue", "violet", "cyan", "white"] )) #We check if val is a correct color.
s.color = val;
else
error ([mfilename " :::: Expecting the value for ""color"" to be a correct color."]);
endif
else
set#entity (s, prop,val);
endif
endwhile
endfunction
I'll add more details:
A simple example could be the next two classes:
try1, constructor and method (in his folder #try1):
function t = try1(x)
t.n = x;
t = class (t, "try1")
endfunction
function o = op(t,x)
o = t.n + x;
endfunction
try2 inherits from try1, constructor and method(in his folder #try2):
function t2 = try2(x)
t1 = #try1(x);
t.n = x;
t2 = class (t, "try2",t1);
endfunction
function o = op(t,x)
o = t.n - x;
endfunction
How to acces to op method of try1 with an instance of try2?
thanks :)
If you want to access the constructor of the parent class, just call it as you would normally outside the child class. Like so:
$ cat #try1/try1.m
function t = try1 (x)
t.n = x;
t = class (t, "try1");
endfunction
$ cat #try1/op.m
function o = op (t)
disp ("op() from try1");
o = t.n + 5;
endfunction
$ cat #try2/try2.m
function t2 = try2 (x)
t1 = #try1 (x);
t.n = x;
t2 = class (t, "try2", t1);
endfunction
$ cat #try2/op.m
function o = op (t)
o = op (t.t1);
endfunction
$ octave
octave:1> try2 (5)
ans = <class try2>
octave:2> op (ans)
op() from try1
ans = 10
See the manual section on Object Oriented Programming, specially the section on Inheritance and Aggregation
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