Child class constructor method in Lua
Asked Answered
N

2

7

Having a bit of a hard time to grasp the concept of inheritance (and metatables) in Lua. The official tutorial doesn't specifically explain how to make a constructor for the child class.

The problem with my example is that player:move() is nil, so player is still an Object class

-- Generic class
Object = {}
function Object:new (type,id,name)
    o = {}
    self.type = type or "none"
    self.id = id or 0
    self.name = name or "noname"
    setmetatable(o, self)
    self.__index = self
    return o
end

function Object:place(x,y)
    self.x = x
    self.y = y
end

-- Player class
Player = Object:new()

function Player:new(id,name)
    o = Object:new("player",id,name)
    o.inventory = {}
    o.collisions = {}
    return o
end

function Player:move(x,y)
    return print("moved to " ..x.." x " .. y)
end

local player = Player:new(1, "plyr1")
player:move(2,2)
Namaqualand answered 12/10, 2016 at 17:34 Comment(0)
B
2

In the constructor Player:new, we are returning an object of Object class through the following line:

o = Object:new("player",id,name)

Once we remove that, player:move() will be called:

moved to 2 x 2

The reason is, even though we are calling the Player:new constructor, we are returning therein actually an instance of Object class. o is in inherited property in this case.

Bowknot answered 12/10, 2016 at 17:56 Comment(0)
B
4

Example on classes inheritance

Generic class

Object = {}

function Object:__tostring()
   if rawget(self, "type") then  -- only classes have field "type"
      return "Class: "..tostring(self.type)
   else                          -- instances of classes do not have field "type"
      return 
         "Type: "..tostring(self.type)..", id: "..tostring(self.id)
         ..", name: "..tostring(self.name)
   end
end

function Object:newChildClass(type)  -- constructor of subclass
   self.__index = self
   return
      setmetatable({
         type = type or "none",
         parentClass = self,
         __tostring = self.__tostring
      }, self)
end

function Object:new(id, name)        -- constructor of instance
   self.__index = self
   return
      setmetatable({
         id = id or 0,
         name = name or "noname"
      }, self)
end

function Object:place(x,y)
   self.x = x
   self.y = y
end

Player class

Player = Object:newChildClass("player")

function Player:new(id,name)
  local o = Player.parentClass.new(self, id, name)  -- call inherited constructor
  o.inventory = {}
  o.collisions = {}
  return o
end

function Player:move(x, y)
   self:place(x, y)
   print("moved to (" ..self.x..", " .. self.y..")")
end

local player = Player:new(1, "plyr1")
print(player)     -->  Type: player, id: 1, name: plyr1
player:move(2,2)  -->  moved to (2, 2)

How to make subclass and call inherited method

Dog = Player:newChildClass("dog")

--- we want to override method "move" in class "dog"
function Dog:move(x, y)
   Dog.parentClass.move(self, x, y)  -- call inherited method "move"
   print("Woof!")   -- dog says "woof" after every move
end

local dog = Dog:new(42, "dg42")
print(dog)       -->  Type: dog, id: 42, name: dg42
dog:move(3,4)    -->  moved to (3, 4)
                 -->  Woof!
Bhili answered 12/10, 2016 at 20:28 Comment(1)
It's crazy. Such a massive workaround for such a basic feature. Thank you for your example codeEconomically
B
2

In the constructor Player:new, we are returning an object of Object class through the following line:

o = Object:new("player",id,name)

Once we remove that, player:move() will be called:

moved to 2 x 2

The reason is, even though we are calling the Player:new constructor, we are returning therein actually an instance of Object class. o is in inherited property in this case.

Bowknot answered 12/10, 2016 at 17:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.