Inheritance Issue - attempt to call missing method 'methodName' of table

  1. What do I want to achieve?

Recently, I have been trying to better learn OOP and Inheritance practices. I have been trying to just create some basic examples based off tutorials to better understand. Currently, I have my BaseClass which contains both properties and methods. I then, have a subclass that inherits some properties from the BaseClass but has its own properties and its own methods.

  1. What is the issue?

When defining a custom method inside of my subclass, it does not work whenever I try and call it from inside of a ServerScript. Here is the basic layout I have thus far.

ModuleScript titled Car:

local Car = {}
Car.__index = Car

function Car.new(position, driver, model)
	return setmetatable({
		Position = position,
		Driver = driver,
		Model = model,
	}, Car)
end

function Car:Boost()
	print("This vehichle is boosting, VROOM VROOM!")
end

return Car

ModuleScript titled Truck:

local Car = require(script.Parent.Car)

local Truck = {}
Truck.__index = Car


function Truck.new(position, driver, model, slogan)
	return setmetatable({
		Position = Car.new(position, driver, model).Position,
		Driver = Car.new(position, driver, model).Driver,
		Model = Car.new(position, driver, model).Model,
		Slogan = slogan
	}, Truck)
	
end

function Truck:useSlogan()
	print("testing") -- am planning on using the slogan property here.
end

return Truck

The ServerScript:

local Car = require(game.ServerScriptService.Car)
local Truck = require(game.ServerScriptService.Truck)

local carModel = workspace.Car
local truckModel = workspace.Truck

local newCar = Car.new(carModel.Position, "ImTheBestMayne", carModel)
local newTruck = Truck.new(truckModel.Position, "ImTheBestMayne", truckModel, "slogan test")

newCar:Boost()

newTruck:useSlogan()

print(newTruck)

Whenever I call the method useSlogan() inside the ServerScript, that is when I get the title error ā€œattempt to call missing method ā€˜useSlogan’ of tableā€

However, if the method is located inside of the Car MS and not the Truck MS, it works.

Working setup:

local Car = {}
Car.__index = Car

function Car.new(position, driver, model)
	return setmetatable({
		Position = position,
		Driver = driver,
		Model = model,
	}, Car)
end

function Car:Boost()
	print("This vehichle is boosting, VROOM VROOM!")
end

function Car:useSlogan()
	print("testing")
end

return Car

  1. What solutions have I tried thus far?

Really, just reworking the scripts. I originally tried this iteration of the Truck MS.

local Car = require(script.Parent.Car)

local Truck = {}
Truck.__index = Car


function Truck.new(position, driver, model, slogan)
	local newTruck = Car.new(position, driver, model)
	newTruck.Slogan = slogan
	
	return setmetatable(newTruck, Truck)
end

function Truck:useSlogan()
	print("testing")
end

return Truck

My guess as to why this is happening would be the way the indexing is dealt with inside of the Truck MS. However, this confuses me. My understanding was that with .__index is that Lua would first try and find the method inside of the newTruck table. I can see why this would not work because obviously the useSlogan() method is located inside of the truck table. And whenever the method is located inside of Car, the .__index checks that table, in which it finds the method. Well, then what about this line?

return setmetatable(newTruck, Truck)

This would imply that the newTruck table would first check the newTruck table and THEN the truck table, no? So, then why is the method located inside of the Truck script firing an error when called inside a ServerScript?

Any help is appreciated, thanks in advance.

The reason for this error is because of how __index works.
When you call newTruck:useSlogan() on the ServerScript, this is what ROBLOX does:

  1. It checks if the method :useSlogan() is present inside newTruck: it sees it’s not there, so it moves on;
  2. It checks if newTruck has a metatable with the __index property, which it does;
  3. It checks if the method :useSlogan() is present inside the __index table, which in our case is Car: because Car does not have the :useSlogan() method, the script throws an error.

The best way to fix this issue would be to copy every element of Car inside Truck when creating a new truck, and setting Truck.__index to Truck.
Here’s an example of what I mean:

local Car = require(script.Parent.Car)

local Truck = {}

for i, v in Car do
	Truck[i] = v -- Copy everything from Car into Truck
end

Truck.__index = Truck -- Truck now contains everything Car does, so there is no need to set Car as the __index

function Truck.new(position, driver, model, slogan)
	
	local newTruck = Car.new(position, driver, model)
	newTruck.Slogan = slogan
	
	return setmetatable(newTruck, Truck)
end

function Truck:useSlogan()
	print("testing")
end

return Truck

I hope this helped!

EDIT: If you add any nested tables into Car (something such as Car.Passengers = {}) remember to add a way of making a deep clone of the table!!

1 Like

Thank you for the response. I will test it soon. Well, actually, I got the whole thing to work just by changing this line

Truck.__index = Car

to

Truck.__index = Truck

But I heard this was supposedly really bad practice.

And thanks for the information about nested tables, I will remember it for the future.

Edit: This was the reasoning for why it is a bad idea to set Truck.__index = Truck

  • While not generally recommended due to potential unintended consequences, you could mimic the Car script’s setup by setting Truck.__index = Truck within the Truck script.
  • Caution: This would create a circular reference within the Truck table, which might lead to unexpected behavior in complex scenarios.
1 Like

This is exactly what I was going to say. Its annoying lua doesn’t allow for any sort of inheritance without having to create your own class system. Whilst @lamonLikeTinyGamer solution is good you can also add a function value to __index to handle inheritance.

Truck.__index = function(self, index)
  return rawindex(Truck, index) or rawindex(Car, index)
end

although it isn’t really performance efficient and this particular function doesn’t work well with false cause lua sucks. Also idk if rawindex is a real function i just forgot the exact function name.

1 Like

Is rawget the function you are referring to? Honestly, it is seeming like my error is coming from a beginner understanding of metatables, because I have tried to read through the page about them on documentation, but it is daunting. It contains information about the function I believe you are referring to.

And once again, like I stated above. It is fine to set the .__index to something that is not the ModuleScript in which my subclass is inheriting from?

Thanks.

Yes thank you, I haven’t used lua in quite a while so i forget these things.

I’m very positive that there shouldn’t be any performance issues from doing so since the table is already shared between the two environments and I’ve never heard of such a thing. The only problem with @lamonLikeTinyGamer 's suggestion is that changing the __index to the same Truck class will mean it won’t be able to access the Car class methods.

You fix this by having methods in both module scripts but I would personally try and centralise functions especially within classes since thats one of the main benefits of OOP. However it isn’t neccessary and you can keep it as it doesn’t make too much of a difference.

1 Like

By centralize, do you mean having all my methods in the BaseClass ModuleScript. Honestly, I was aware of this possibility from the start, but I was being stubborn as I did not like that structure. I felt it necessary to have methods only in the subclasses that will utilize them. I,e: Although it was a hypothetical example, people who drive trucks are more likely to tell you about that truck, or have a slogan. People ā€œdrivingā€ a car would not do that, so why would they need access to the :useSlogan() method?

Oh, and the issue with setting .__index = Truck was not about performance. Apparently, it is liable to cause a circular dependency/infinite loop in more complex structures. I am unaware if that is true or not, I just do not want to develop bad practice, so I figured I would ask about other solutions.

I hope I’m not missing something, but the following is a very standard and traditional approach to inheritance:

local Car = require(script.Parent.Car)

local Truck = {}
Truck.__index = Truck
setmetatable(Truck, Car)

function Truck.new(position, driver, model, slogan)
	local newTruck = Car.new(position, driver, model)
	newTruck.Slogan = slogan

	return setmetatable(newTruck, Truck)
end

function Truck:useSlogan()
	print("testing")
end

return Truck

Method not in newTruck? Check in Truck. Method not even in Truck? Check in Car.

1 Like

Thank you for your response. Basically, your response is something I have tried, and it has worked. What I am asking about has basically turned into a different conversation.

local Truck = {}
Truck.__index = Truck
setmetatable(Truck, Car)

I was told that the line Truck.__index = Truck was bad practice and liable to result in circular dependencies/infinite loops in more complex structures.

I also got it work using that method without even the additional setmetatable(Truck, Car) call. I was told this is unnecessary and…

local Truck = {}
Truck.__index = Truck

would suffice, but as stated above, is bad practice.

Is there an issue with not including your first setmetatable call? And could there be adverse effects for the way .__index was set to = Truck?

Thanks again.

1 Like

Yes, I saw the conversation steering more towards deep copying the methods. I guess that works, but copying partially defeats the standard purpose of inheritance, which saves some memory and where all subclasses point to the same base.

setmetatable(Truck, Car) actually is necessary in order to access Car methods. Calling newTruck:Boost() should cause an error.


Perhaps it’s easier to picture what’s happening with three tables. base represents a base class like Car; class represents any inheriting (sub)class like Truck, and self is what the constructor of a (sub)class like Truck returns.

Case 1:

local base = {baseKey = "xD"}
local class = {classKey = ":D"}
class.__index = base

local self = setmetatable({}, class)
print(self.baseKey) --> xD
print(self.classKey) --> nil
  • class acts as a metatable to self.
  • The VM invokes __index in class (metatable of self) pointing towards base.
  • At no stage does it point to the class itself, thus classKey is nil.

Case 2:

local base = {baseKey = "xD"}
base.__index = base
local class = {classKey = ":D"}
class.__index = class
setmetatable(class, base)

local self = setmetatable({}, class)
print(self.baseKey) --> xD
print(self.classKey) --> :D
  • class again acts as a metatable to self.
  • The VM invokes __index in the metatable of self, this time pointing to class.
  • Oh well, nothing was found, but luckily class has a metatable called base with an __index to invoke.
  • The second __index now points towards the base and finds a joyful smile.

It is fine to shorten the code with class.__index = setmetatable(class, base).


I considered this and admit to find the problem a bit vague without a concrete example. Circular dependency can be problematic when modules start requiring and depending on each other interchangably, which can also happen if the hierarchical order breaks. Still, a well structured code base aims for some level of directionality.


Lastly, in terms of __index performance, as Roblox put it, the compiler performs some witchcraft to optimise __index pointing to a table, so they strongly recommend it in OOP. They only generally advise against long chains and __index functions (source).

Parent class:

local Item = {}
Item.__index = Item

function Item.new(name)
	local self = setmetatable({}, Item)

    self.ID = nil

	return self
end

return Item

Child class:

local Weapon = setmetatable({}, ItemClass)
Weapon.__index = Weapon

function Weapon.new(weaponName)
	local self = setmetatable(ItemClass.new(weaponName), Weapon)

    self.SubType = nil
	
	return self
end

return Weapon

This has worked for me with 5+ descendants and no issues.

Thanks for the in-depth explanation as well as examples. I’ll mark as solution, but I want to give other people chances to share. I’ll try to adapt this practice into my future structures.

No problem, I hope it cleared some things up. In short, the VM checks whether a table has a metatable and invokes the metamethods it finds in it. __index points it toward a place to look, which in this case is the metatable itself. But this metatable has it’s own metatable, which also has an __index pointing to itself etc.

This is all fine as long as the chain is not excessively long. At that point you might want to reconsider the whole structure and its convenience anyway. Perhaps you find entity-component systems (ECS) to solve some tasks better.


Just wanted to add, if you look closely, SideProgrammer’s class is almost exactly the same, except some parts are condensed in one line, like ItemClass.new() respectively Car.new() assigned a metatable right away.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.