hey I was looking at this topic https://www.lexaloffle.com/bbs/?tid=2951
and I was wondering how to implement method inheritance
obj = {} obj.x = x obj.y = y obj.w = 8 obj.h = 8 obj.xspd= 0 obj.yspd= 0 obj.tile= 0 obj.size= 0 function obj:create(...) local c --copy table if type(self) == "table" then c = {} for k, v in pairs(self) do c[k] = copy(v) end else c = self end return c end function obj:update() --keep in bounds if (self.x < 0+self.w/2) self.x = 0+self.w/2 if (self.x > 127-self.w/2) self.x = 128-self.w/2 if (self.y < 0+self.h/2) self.y = 0+self.h/2 if (self.y > 127-self.h/2) self.y = 128-self.h/2 end function obj:render() --draw spr(self.tile, self.x+self.w/2, self.y+self.h/2, self.size, self.size) end |
plr = obj:create() --init plr.x = 64 plr.y = 112 plr.w = 8 plr.h = 8 plr.xspd = 3 plr.yspd = 0 plr.tile = 5 plr.size = 1 --power up flags plr.is_mag = false plr.is_wav = false plr.is_rkt = false --update event function plr:update() base:update() --I want this to call the code from the obj:update() --move if btn(0) then self.x = self.x + -self.xspd end if btn(1) then self.y = self.y + self.xspd end end --I want draw event to automatically be inherited since I am not calling it |
Your reference article is too old. Pico now supports grt/setmetatable. It basically adds fallback mechanism to lua attribute lookup.
note: it is rather useless behond educationnal purposes, as it uses a lot of token for something that can easily be done otherwise.
well I am just trying to create a object system that supports instances and method inheritance/override
this would actually take up less space in the long run.
I appreciate the sensitivity to token use but I don't think it's impractical. The baseline constructor with prototypical method inheritance is 16 tokens.
this question still hasn't quite been answered
I'm trying to inherit methods or table functions
Actually, it has been answered - using metatable, LUA will first try to call the method in the current table then look up the metatable chain.
However, there is no magic trick of calling the base function if it is redefined in a child class (like any other OO language I know of).
I need to call the base method as it reduces the amount of repeating code
You want to call the superclass method from an overridden method. The 16 token example I linked to in the wiki provides inheritance and overriding, but does not provide parent class access. For small Pico-8 programs, a simple cheat probably suffices: refer directly to the parent method from the child method.
parentclass = {} function parentclass:new(o) self.__index = self return setmetatable(o or {}, self) end function parentclass:method(n) return n + n end childclass = parentclass:new() function childclass:method(n) parent_result = parentclass.method(self, n) return parent_result + 1 end o1 = parentclass:new() print(o1:method(5)) -- 10 o2 = childclass:new() print(o2:method(5)) -- 11 |
Notice that "parentclass.method(self, n)" uses dot notation instead of colon notation, and passes in the instance of childclass (self) explicitly. This allows parentclass.method() to refer to another member on the object and still honors childclass's overrides. (This may not be what you want! Different languages handle this bit differently.)
This cheat of referring to parentclass explicitly is generally considered insufficient because it tightly couples the child method to the parent class. If you want to change the inheritance hierarchy later, you have to remember to update these parent class references. To solve this, you can beef up the constructor pattern (or write a class-maker helper function) to accept and store an explicit reference to the parent class.
The general idea is that Lua does not provide its own class system. It provides a few primitives with which you can make your own.
Here's a decoupled version using a simple "make_class()" helper that isn't too fancy:
function make_class(parentcls) return { parent = parentcls, new = function(self) self.__index = self local obj = parentcls and parentcls:new() or {} return setmetatable(obj, self) end } end parentclass = make_class() function parentclass:method(n) return n + n end childclass = make_class(parentclass) function childclass:method(n) parent_result = self.parent.method(self, n) return parent_result + 1 end o1 = parentclass:new() print(o1:method(5)) -- 10 o2 = childclass:new() print(o2:method(5)) -- 11 |
this is what I wanted. thankyou.
EDIT: ok so I was testing this method out and I get..
"attempt to perform arithmetric on feild 'x' a nil value"
this is my code
function class(par) return { base= par, new = function(self) self.__index = self local obj = par and par:new() or {} return setmetatable(obj, self) end } end obj = class() obj.x = 0 obj.y = 0 obj.w = 8 obj.h = 8 pad = class(obj) pad.w = 16 pad.h = 4 function _draw() rect(obj.x,obj.y,obj.x+obj.w,obj.y+obj.h) rect(pad.x,pad.y,pad.x+pad.w,pad.y+pad.h) --throws error end |
also I tried making the class use the _call meta method and it broke it even more
function class(par) return { base=par, self.__call =function(self) self.__index=self local inst=par and par:new() or {} return setmetatable(inst, self) end } end |
@dddaaannn I am still wondering about this
Not sure what @dddaann wanted to do with the 'new' method but, indeed, it doesn't work :[
Fixed version:
function class(par) local o={} return setmetatable(o,{__index=par or {}}) end obj = class() obj.x = 2 obj.y = 4 obj.w = 8 obj.h = 8 pad = class(obj) pad.w = 16 pad.h = 4 function _draw() cls() rect(obj.x,obj.y,obj.x+obj.w,obj.y+obj.h) rect(pad.x,pad.y,pad.x+pad.w,pad.y+pad.h) -- ok end |
note: getting to understand copy/pasted code is always a Good Thing (tm). Suggest to have a look at: http://lua-users.org/wiki/MetamethodsTutorial
your method doesn't allow base method calling
function class(par) local o={} return setmetatable(o,{self.base = par, __index=par or {}}) end obj = class() obj.x = 2 obj.y = 4 obj.w = 8 obj.h = 8 obj:draw = function() rect(self.x,self.y,self.x+self.w,self.y+self.h) -- self is not passed end pad = class(obj) pad.w = 16 pad.h = 4 pad.draw = function() self.base:draw() --doesn't work end bal = class(obj) bal.w = 8 bal.h = 8 --automaticly inherit obj draw event (also doesn't work) function _draw() cls() obj:draw() pad:draw() bal_draw() end |
The Lua class pattern I cited establishes a "class object" and an "instance object". My make_class() function (and your class() function) returns a class. To get an instance of the class, call the class's new() method.
I dropped prototypical inheritance from my example. It looks like from your code that you want to preserve prototypical inheritance, such that the "obj" instance's x and y properties are inherited by the "pad" instance. You can do both:
function class(par) return { base= par, new = function(self, o) self.__index = self local obj = par and par:new(o) or o or {} return setmetatable(obj, self) end } end classa = class() obj = classa:new() obj.x = 0 obj.y = 0 obj.w = 8 obj.h = 8 classb = class(classa) pad = classb:new(obj) pad.w = 16 pad.h = 4 function _draw() rect(obj.x,obj.y,obj.x+obj.w,obj.y+obj.h) rect(pad.x,pad.y,pad.x+pad.w,pad.y+pad.h) end |
Walking through this:
classa = class() |
This creates a new class called "classa". It has no parent class.
obj = classa:new() obj.x = 0 obj.y = 0 obj.w = 8 obj.h = 8 |
This creates a new instance of classa called "obj". It has no parent object. This sets the x, y, w, and h properties of "obj".
classb = class(classa) |
This creates a new class called "classb". Its parent class is classa.
pad = classb:new(obj) pad.w = 16 pad.h = 4 |
This creates a new instance of classb called "pad". Its parent object is obj. It overrides the w and h properties from obj. When something accesses pad.w, it notices that pad has a "w" property and uses it. When something accesses pad.x, it notices that pad doesn't have that property and falls back to obj.x.
Notice that prototypical inheritance via metatables is doing the work here. The parent class mechanism simply remembers the class hierarchy, in case a method of a child class wants to refer to a method on the parent class (which is what you asked for originally).
[Please log in to post a comment]