Log In  

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 
P#48810 2018-01-31 21:47 ( Edited 2018-02-08 08:02)

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.

P#48818 2018-02-01 02:04 ( Edited 2018-02-01 07:04)

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.

P#48867 2018-02-01 21:43 ( Edited 2018-02-02 02:43)

There is no ‘long run’ in 8192 tokens ;)

P#48871 2018-02-02 01:55 ( Edited 2018-02-02 06:55)

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.

http://pico-8.wikia.com/wiki/Setmetatable

P#48900 2018-02-02 17:02 ( Edited 2018-02-02 22:02)

this question still hasn't quite been answered
I'm trying to inherit methods or table functions

P#48909 2018-02-02 21:17 ( Edited 2018-02-03 02:17)

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).

P#48919 2018-02-03 11:02 ( Edited 2018-02-03 16:02)

I need to call the base method as it reduces the amount of repeating code

P#48925 2018-02-03 14:23 ( Edited 2018-02-03 19:23)

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.

P#48948 2018-02-04 01:34 ( Edited 2018-02-04 06:37)

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
P#48949 2018-02-04 01:48 ( Edited 2018-02-04 06:48)

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
P#48981 2018-02-04 17:37 ( Edited 2018-02-05 00:16)

@dddaaannn I am still wondering about this

P#49040 2018-02-06 14:54 ( Edited 2018-02-06 19:54)

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

P#49044 2018-02-06 16:52 ( Edited 2018-02-06 21:52)

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
P#49074 2018-02-07 22:50 ( Edited 2018-02-08 03:53)

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).

P#49078 2018-02-08 03:02 ( Edited 2018-02-08 08:02)

[Please log in to post a comment]