What are the type of scenarios Metatables are useful for?

Hello, as a Roblox Developer I believe that I should go above and beyond and learn Lua Functions or Roblox incorporated functions to boost my knowledge and to overall strengthen my learning abilities and concepts of scripting. I would like to know what types of uses Metatables can provide, what they’re used for and what type of scenarios (cars, etc) need them.

1 Like

I personally use them for OOP (there’s a good tutorial of it on the dev forums here). There’s a lot of useful stuff to them specifically relating to that - like creating your own classes & defining how those should work.

The link to the OOP guide:

4 Likes

I mainly used them when I am scripting OOP classes that need to inherit some attributes from its super class for example:

local SubClass = {}
SubClass.__index = SubClass
setmetatable(SubClass,{
__index = SuperClass --This will allow the subclass to inherit functions from the superclass
})
3 Likes

A good example of using metatables: Parties (like in RPG games)

You have a “leader” variable, a “members” array, some methods such as RemoveMember, AddMember, ChangeLeader, etc.

You can do all of this and make each party an object.

Something like this:

local party = PartyModule.new()
party:SetLeader(player1)
party:AddMember(player2)
party:AddMember(player3)

for _, member in next, party:GetMembers() do
    member.Character.Humanoid.Health = member.Character.Humanoid.MaxHealth
end

party:RemoveMember(player2)
4 Likes

You use them in OOP Lua all the time! Say I have a Vector4 class as defined below:

local Vector4 = {}
Vector4.__index = Vector4

function Vector4.new(x, y, z, w)
    local self = setmetatable({}, Vector4)
    self.x = x
    self.y = y
    self.z = z
    self.w = w
    return self
end

function Vector4:__tostring()
    return ("Vector4 { %d, %d, %d, %d }"):format(self.x, self.y, self.z, self.w)
end

Every time I call Vector4.new, I get a table in return, with the Vector4 class as the metatable. This meams we can declare metamethods directly inside the class - for example how I did it with __tostring. Also, I declare __index at the top to point at the class, which allows us to access the functions of Vector4 through that returned object.

Thus, I can do this:

local vec = Vector4.new(1, 2, 3, 5)
print(vec) --> Vector4 { 1, 2, 3, 5 }

and it works as expected. It gets juicier when it comes to operator overloading, too!

function Vector4:__add(other)
    -- code that creates a new vector4 by adding this vector4 and the given other vector4
end

...

local v1 = Vector4.new(1, 2, 3, 4)
local v2 = Vector4.new(2, 4, 6, 8)
print(v1 + v2) --> Vector4 { 3, 6, 9, 12 }
4 Likes

What? That has nothing to do with metatables.

1 Like

Except it does.

I didn’t explain how the actual methods work but here’s an example:

function party.new(player)
	local self 			= setmetatable({}, {
		__index = party,
		__tostring = function(self)
			return self.leader
		end;
		
	});
	self.leader 		= player
	self.members 		= {[player] = true}
	
	AddParty(self)
	
	return self
end

--=========//=========//=========//=========//=========//=========//
-- Set methods

function party:ConvertMembersListToArray()
	local tb = {}
	for member, _ in next, self.members do
		tb[#tb+1] = member
	end
	return tb
end

function party:AddMember(playerToAdd)
	if not game:GetService("Players"):FindFirstChild(playerToAdd.Name) then
		return "Player doesn't exist!", false
	end
	
	if self.members[playerToAdd] then
		return "Player is already in party!", false
	end
	
	
	if self:GetMemberCount() >= 4 then
		return playerToAdd.Name .. " tried to join. Party was full!", false
	end
	
	self.members[playerToAdd] = true
	return playerToAdd.Name .. " joined the party!", true
end

function party:RemoveMember(playerToRemove)
	if self.members[playerToRemove] then
		self.members[playerToRemove] = nil
		PartyRequester:FireClient(playerToRemove, "LeaveCurrentParty")
	end
	
	if self:GetMemberCount() == 1 then
		self:RemoveMember(next(self.members))
		return
	end
	
	if self.leader == playerToRemove then -- if the player who left is the leader of a party, we need to change the party's leader or delete the party
		ServerComm:Fire("PartyLeaderLeave", playerToRemove)
		if self:GetMemberCount() > 0 then -- if there are other members, need to change the leader
			local newLeader, _ 		= next(self.members)
			self.leader 			= newLeader
			---- If there's only 1 member left, just remove from party ----
			PartyRequester:FireClient(newLeader, "Notification", "You are the new party leader!", true)
		else
			self:Destroy()
			return
		end
	end 
end

Note: This is all inside a module

2 Likes

The __tostring which you didn’t show at all in your code-sample, sure, but instead of the __index = party you could just as easily use a deep copy function which is what lots of modules/classes do.

1 Like

Yes, I know I didn’t explain it, but he specifically said:

I gave an example of what metatables could be used for, and the first thing that came to my mind was parties. I used metatables for my party system and I believe it’s a pretty straightforward example of how metatables can be used for OOP.

1 Like

Hello, thank you for all of your great replies! It has caught my interest with some of the posts you guys made. Majority of the stuff I’m hearing is OOP (Object Orientated Programming) Which I have done very little programming in Java which is a OOP language so I think I have some knowledge around that topic, however, there are some things that I am still confused about like self.Value I do not understand how or why you should use self for, can someone please give an explanation on this?

So real quick, self arguments are sugar syntax for including the table that the function came from as the first argument.


So this:

Object:Method(a, b)

Would be the same as this:

Object.Method(Object, a, b)

And whenever you are constructing functions, this:

function Class:Method(a, b)
	-- code here
end

Would be the same as this:

function Class.Method(self, a, b)
	-- code here
end
3 Likes

Metatables are preferable to deep copying. I’m not sure what you mean when you say most modules do it - deep copying would introduce a lot of overhead compared to metatables when you instantiate objects?

2 Likes

Isn’t it more memory efficient to use .__index instead of creating deep copies when creating classes in lua?

2 Likes

(also: @Elttob)
I wasn’t saying that it was a bad idea to use __index for this, just that his original code was unclear where/why he would use metatables. In terms of performance, it doesn’t really matter which way you use if you don’t have very many functions (which this example didn’t).

1 Like

Metatables in summary are great for OOP. In other words, you create an object with variables, functions but also special functions(metamethods(?)).

Scenarios include:

  • Cars
  • Parties
  • Anything that is a template of something

Classes are somewhat like a template for things in non-technical terms.

1 Like

the self parameter is just basically passing the entire table itself for example say you have a OOP class like this:

local CarClass = {}
CarClass.__index = CarClass
CarClass.new = function(Name,Speed)
      CarClass.Name = Name 
      CarClass.Speed = Speed
end
CarClass.GetDeltaSpeed = function(self,newSpeed)
--the self argument means we are taking the table as a argument too
--so now we can simply do this
     return newSpeed - self.Speed--the original speed was assigned in the new function above
end
2 Likes

Once again, thanks for all of the replies! By posting this thread I have learned some usages of Metatables, like OOP (Object Orientated Programming) and I have to say OOP is really useful! I have also learned from my experience (testing that i’ve done for some time) that self is basically a value of the object you called the function on? Like the Speed Changer function used in the OOP Lesson in the first reply of this thread. Correct me if I’m wrong please.

I would recommend not using metatables to OOP or to even OOP at all.
Literally all the 4 pillars of OOP are lies or can be done with procedural or functional programming

// watch this video if u want more info

1 Like