Different Methods of Writing Classes?

Hello! I’m trying to get back into the swing of developing on Roblox, and I randomly decided to look into object-oriented programming. It looks like the method that is most commonly taught is different than the one that I observed and picked up from studying other code. I’m hoping to learn why this difference is integral.

METATABLE METHOD
To have object-oriented programming most videos and forum tutorials recommend doing this: (contained within module script)

local Object = {}
Object.__index = Object

function Object.new(name, color)
	local object = setmetatable({}, object)
	object.Name = name
	object.Color = color
	
	return object
end

function Object:Speak()
	print(self.Name)
end

METATABLELESS METHOD
However, the first form of classes I encountered (and what I have been replicating) looks like this:

local Object = {}

function Object.new(name, color)
	local self = {}
	local name = name
	local color = color

	function self.Speak()
		print(name)
	end
	
	return self
end

Although both systems function practically identically, I understand that they have some notable differences – namely that the metatableless system does not allow the variables to be directly referenced or changed. With that in mind, I want to ask if there is a reason that the metatable method is taught? Is it better? If so, is there ever a reason to use the metatableless method?
Thanks! ^^

2 Likes

Using metatables in your classes saves memory.
When your system looks like the one in your first code snippet, the class functions are only created once and then referenced through the metatable. In your “metatableless method”, the Speak function is created every time you instantiate an object with Object.new.

For example, if you were to make a “Dog” class that could Eat, Walk, Run, Bark, and Sleep without metatables, you would be allocating memory for an Eat, Walk, Run, Bark, and Sleep function for each dog object you create. If you wanted to have, say, 1,000 dogs in your game… then you would be creating 5,000 functions unnecessarily, when you could have just 5. I hope you can see how that can be less than ideal :P​

If you are unsure how exactly metatables save memory, basically, if you try to index a value that doesn’t exist in a table, Lua will try to instead do the same lookup in the table that __index points to (if the table has a metatable with __index that is).

local t = {}
local t2 = { someKey = "Hello world!" }

setmetatable(t, { __index = t2 })

print(t.someKey) --> "Hello world!"

You can see that “Hello world!” is printed, even though the table t doesn’t have any value at someKey.

This means you can just shove your class functions into the metatable’s __index (which is exactly what the first code snippet is doing) and then use these functions by calling them on the object.

local obj = Object.new()
obj:Speak()

Metatables also allow you to implement class inheritance semi-easily (and likely other things I can’t think of currently).

I can’t think of any reason to avoid metatables for your Lua classes, unless you are trying to create some sort of encapsulation system that prevents access to some of the objects’ properties (I don’t know why you would want to do that).

2 Likes

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