How can I clean up this structure for multi-level inheritance?

What can I do to improve this setup for inheritance? __index looks like it has a little too many operations, but I couldnt find a way to reduce that

-- the __index used by all classes and function to generate metatables supported by __index
local __index = function(self, index)
  local metatable = getmetatable(self)
  return
    rawget(self, index) or
    (metatable.staticVariables or {})[index] or
    (metatable.parent or {})[index]
end
local function generateMetatable(parent, staticVariables)
  return {
    __index = __index,
    parent = parent,
    staticVariables = staticVariables,
  }
end

-- class1
local class1StaticVariables = {
  a = 10,
}
local function newClass1(name)
  local self = setmetatable(
    { name = name },
    generateMetatable(nil, class1StaticVariables)
  )
  return self
end

-- class2 that inherits class1
local class2StaticVariables = {
  b = 20,
}
local function newClass2(name, age)
  local self = setmetatable(
    { age = age },
    generateMetatable(newClass1(name), class2StaticVariables)
  )
  return self
end

-- class3 that inherits class2
local class3StaticVariables = {
  c = 30,
}
local function newClass3(name, age, hairColor)
  local self = setmetatable(
    { hairColor = hairColor },
    generateMetatable(newClass2(name, age), class3StaticVariables)
  )
  return self
end

-- test
local myClass3 = newClass3("Steve", 22, "Purple")
print(myClass3.hairColor)
print(myClass3.c)
print(myClass3.age)
print(myClass3.b)
print(myClass3.name)
print(myClass3.a)

I considered storing parent and staticVariables inside of the object instead of the object’s metatable so I could just have a single metatable shared between every class, but then putting metadata like parent inside of an object’s values might cause issues

also, I noticed while typing up this post that I could change parent to be a table to support inheriting from multiple classes, like java’s class Test extends Parent1, Parent2. I’ll add that later as a reply

2 Likes

With some changes from @bigometer10000000000, now there isn’t a function used for __index by setting __index on the classSomethingStaticVariables tables

-- class1
local class1StaticVariables = {
  a = 10,
}
local function newClass1(name)
  local self = setmetatable(
    { name = name },
    { __index = class1StaticVariables }
  )
  return self
end

-- class2 that inherits class1
local class2StaticVariables = setmetatable(
  { b = 20 },
  { __index = class1StaticVariables } --static variables now default to the parent's static variables
)
local function newClass2(name, age)
  local self = setmetatable(
    newClass1(name), --children are now instances of their parents with the children's instance variables added
    { __index = class2StaticVariables } --children may still have their own static variables
  )
  self.age = age
  return self
end

-- class3 that inherits class2
local class3StaticVariables = setmetatable(
  { c = 30 },
  { __index = class2StaticVariables }
)
local function newClass3(name, age, hairColor)
  local self = setmetatable(
    newClass2(name, age),
    { __index = class3StaticVariables }
  )
  self.hairColor = hairColor
  return self
end

-- test
local myClass3 = newClass3("Steve", 22, "Purple")
print(myClass3.hairColor)
print(myClass3.c)
print(myClass3.age)
print(myClass3.b)
print(myClass3.name)
print(myClass3.a)
2 Likes