▲ 4 r/lua

Advice needed on prototype-based OOP

Hi all,

I'm quite new to Lua and I've been reading through Programming in Lua 4th edition. The section on OOP outlines a common prototype-based approach for simulating the function of classes. Here's an example:

   Shape = {x=0, y=0}

   function Shape:new(o)
      o = o or {}
      self.__index = self
      setmetatable(o, self)
      return o
   end

We can easily inherit from shape and give it some new default parameters and new methods:

Rectangle = Shape:new({width=100, height=100})

function Rectangle:getPerimeter()
    return self.width * 2 + self.height *2
end

myRect = Rectangle:new({x=50, y=100, width=300, height=100})

print(myRect:getPerimeter()) 

--prints 800

Okay, so this is all described well in various guides. But what I can't seem to find out, is what the correct way is to initialise some values on the creation of an object using the inherited prototype. So let's say, instead of always calculating my perimeter whenever I want it, I wish to store the perimeter when the rectangle object is created, thus only doing that calculation once. What is the best way of doing this?

My current solution looks something like this:

Shape = {x=0, y=0}
function Shape:new(o)
    o = o or {}
    self.__index = self
    setmetatable(o, self)
    self.init(o)
    return o
end
function Shape:init()
end

Rectangle = Shape:new({width=100, height=100})
function Rectangle:init()
    self.perimeter = self.width * 2 + self.height *2
end

Notice how ive had to pass in o, instead of using the normal self:method Notation? This is because when init is called, self refers to the Shape prototype, not the instance of a shape. The instance is in o.

Infact, we have the same issue even without inheritance:

Rectangle = {x=0, y=0, width=100, height=100}
function Rectangle:new(o)
    o = o or {}
    self.__index = self
    setmetatable(o, self)
    
    --if I want to dynamically set the perimeter, I have to do so on o, rather than on self
    o.perimeter = width * 2 + height * 2 --this works
    self.perimeter = width * 2 + height * 2 --this would set perimeter for the prototype itself, not the object
    return o
ens

This seems.... Messy. Particular with inheritance. I can't help but feel like I'm missing a trick. Any help would be greatly appreciated.

reddit.com
u/Barldon — 19 days ago