Full tutorial about OOP

In each table you can create a special table for the player and this is better for controlling the players better (e.g I have a specific player that I must store in Metatable and Checking for his Health)

--This is the main module table. It will hold both the constructor (.new) and any methods (like DoSomethingPlease).
local Module = {}

function Module.new(player: Player)
	--setmetatable(..., Module) sets the metatable of self to Module, allowing method lookups like self:DoSomethingPlease() to work.
	local self = setmetatable({
		player = player,	
		Character = player.Character or player.CharacterAdded:Wait()
		
	}, Module)
	
	print(self) --> shows the object and its contents
	
	--Because Lua will look for missing keys (like methods) in the metatable (which is Module), this is how self gains access to DoSomethingPlease
	--prints the function reference
	print(self:DoSomethingPlease) --> 100 Health
	
	return self
end

function Module.DoSomethingPlease(self): number
	--It returns the current health of the player humanoid
	return self.Character.Humanoid.Health
end

return Module

__index

index__ The indexing access operation table[key] This event happens when table is not a table or when key is not present in table. The metavalue is looked up in the metatable of table. The
:disappointed_relieved: metavalue for this event can be either a function, a table or any value with an __index metavalue

--count will be used to track how many "checks" (missing key accesses) are made
local oldtable = {count = 0}

local table = setmetatable(oldtable, {	
	__index = function(self, _k)
		--The __index function is triggered whenever you try to access a key that doesn’t exist in the table
		self.count = self.count + 1
		return self.count
	end,
})

--These keys (Hi, Testing, 155) do not exist in the table

print(t.Hi)		 -- 1
print(t.Testing) -- 2
print(t[155])	 -- 3

Some example here about index :relaxed:

local tab1 = {foo = 'bar'}
local tab2 = setmetatable({}, {__index = tab1})

print(tab2.foo) --> 'bar'

__newindex

__NewIndex is my favorite and I prefer to use it most of the time because it checks if there is anything new or not and if there is something new it will send it to the function but I heard about it as a hacker loophole I don’t know :thinking:

local Table = setmetatable({}, {	
	
	--Instead of actually storing the key-value pair in the table
	__newindex = function(self, _k, v)
		print(_k) --> Hi or YSH or Hello
		
		--rawset bypasses the __newindex call and stores the key-value pair directly in the table
		rawset(self, _k, v)
	end,
})


Table.Hi 	= 1
Table.Hello = 2
Table.YSH	= 3

print(Table.Hi) --> 1

__concat

local table = {
	__concat = function(a, b)
		return tostring(a) .. tostring(b)
	end
}

local t1 = setmetatable({name = "Hello "}, table)
local t2 = setmetatable({name = "World"}, table)

print(t1 .. t2) --> table: 0x...table: 0x... (default tostring, unless overridden)

so you can’t read anything here so let’s use __tostring here

local table = {
	__tostring = function(t) 
		return t.name
	end,
	
	
	__concat = function(a, b)
		return tostring(a) .. tostring(b)
	end
}

local t1 = setmetatable({name = "Hello "}, table)
local t2 = setmetatable({name = "World!"}, table)

print(t1 .. t2) --> Hello World!

__unm

table1 = {
	new = function(x, y)
		return setmetatable({x = x, y = y}, table1)
	end,
	
	__unm = function(v)
		return table1.new(-v.x, -v.y)
	end
}


-- Usage:
local a = table1.new(3, 4)
local b = -a

print(b.x, b.y) --> -3  -4

__len

local Variables = {"Hello world", "YSH", "Justin Bieber"} -- i don't know what i have to type here ignore it please
local Functions = {
	__len = function(v)
		local insidetable = 0
		
		for _ in pairs(v) do
			insidetable += 1 
		end
		
		return insidetable
	end
}

local table = setmetatable(Variables, Functions)

print(#table) -- printing 3

__tostring

-- create a new metatable to get sum of elements of the main table
table1 = setmetatable({ 10, 20, 30 }, {
	__tostring = function(mytable)
		local sum = 0

		for k, v in pairs(mytable) do
			sum = sum + v
		end

		return "The sum of values in the table is " .. sum
	end
})

--First all the numbers will be taken and added to a single number by using `+` and converted into a string
print(table1) 

Calculation operators

so i’ll just gonna talk about the importants things like

  • sub__ Changes the behavior of operator -
  • mul__ Changes the behavior of operator *
  • div__ Changes the behavior of operator /
  • mod__ Changes the behavior of operator %
  • eq__ Changes the behavior of operator ==
  • lt__ Changes the behavior of operator < or >
  • le__ Changes the behavior of operator <= or =>

local A = {1}
local B = {1}
--both A and B are simple tables holding one numeric value

local table = {
	--defines what happens when two tables using this metatable are added together +
	__add = function(a, b)
		--the addition (+) operation. If any operand for an addition is not a number, Lua will try to call a metamethod
		
		print("Add")
		return {a[1] + b[1]} --> 1 + 1
	end,
	
	__sub = function(a, b)
		--the subtraction (-) operation. Behavior similar to the addition operation
		
		print("Sub")
		return {a[1] - b[1]} --> 1 - 1
	end,
	
	__mul = function(a, b)
		--the multiplication (*) operation. Behavior similar to the addition operation
		
		print("Mul")
		return {a[1] * b[1]} --> 1 * 1
	end,
	
	__div = function(a, b)
		--the division (/) operation. Behavior similar to the addition operation
		
		print("Div")
		return {a[1] / b[1]} --> 1 / 1
	end,
	
	__mod = function(a, b)
		--the modulo (%) operation. Behavior similar to the addition operation
		
		print("Mod")
		return {a[1] % b[1]} --> 1 % 1
	end,
	
	__pow = function(a, b)
		--the exponentiation (^) operation. Behavior similar to the addition operation
		
		print("Pow")
		return {a[1] ^ b[1]} --> 1 ^ 1
	end,
	
	__idiv = function(a, b)
		--the floor division (//) operation. Behavior similar to the addition operation

		print("idiv")
		return {a[1] // b[1]} --> 1 // 1
	end,
}

setmetatable(A, table)
setmetatable(B, table)

print((A + B)[1]) --> 2
print((A - B)[1]) --> 0
print((A * B)[1]) --> 1
print((A / B)[1]) --> 1
print((A % B)[1]) --> 0
print((A ^ B)[1]) --> 1
print((A // B)[1]) --> 1

Bitwise operators (others not important these things not in Roblox Studio Luau programming language)

  • __bor(a, b): the bitwise OR (|) operation. Behavior similar to the bitwise AND operation.
  • __bxor(a, b): the bitwise exclusive OR (binary ~) operation. Behavior similar to the bitwise AND operation.
  • __bnot(a): the bitwise NOT (unary ~) operation. Behavior similar to the bitwise AND operation.
  • __shl(a, b): the bitwise left shift (<<) operation. Behavior similar to the bitwise AND operation.
  • __shr(a): the bitwise right shift (>>) operation. Behavior similar to the bitwise AND operation.

pairs, ipairs

Same as __pairs() , except for the __ipairs() function

local t = setmetatable({}, {
	__pairs = function(tbl)
		local function iter(array, index)
			index = index + 1
			local value = nil
			if index <= #array then
				value = 1
			end
			if nil ~= value then return index, value end
		end

		return iter, tbl, 0
	end
})

--This stores a key-value pair in the table If you used the default pairs() this would show up in the loop
t.HelloWorld = 1


for i, v in pairs(t) do
	
	--i = HelloWorld
	--v = 1
	print(i, v)
end

__eq

Lua only calls __eq if both tables being compared share the same __eq function (or at least the same metatable) :relaxed:

local A = {1}
local B = {1}

local table = {
	--the equal (==) operation. Behavior similar to the addition operation
	--except that Lua will try a metamethod only when the values being compared are either both tables or both full userdata and they are not primitively equal
	--The result of the call is always converted to a boolean
	__eq = function(a, b)
		
		print("Eq")
		return {a[1] == b[1]}
	end,
}

setmetatable(A, table)
setmetatable(B, table)

print((A == B)) --> True

__It

local A = {1}
local B = {1}

local table = {
	--he less than (<) operation. Behavior similar to the addition operation
	--except that Lua will try a metamethod only when the values being compared are neither both numbers nor both strings
	--Moreover, the result of the call is always converted to a boolean
	
	__lt = function(a, b)
		
		print("It")
		return {a[1] < b[1]} -- It doesn't matter if it's (<) or (>)
	end,
}

setmetatable(A, table)
setmetatable(B, table)

print((A > B)) --> True

__le

By default Lua doesn’t know how to compare tables like table1 <= table2, so it throws an error unless you define a metatable with __le :face_with_spiral_eyes:


local A = {1}
local B = {1}

local table= {
	__le = function(a, b)
		
		print("le")
		return {a[1] <= b[1]} -- It doesn't matter if it's (<=) or (>=)
	end,
}

setmetatable(A, table)
setmetatable(B, table)

print((A >= B)) --> True

for more information here!

I talked about the important things, you can search for more. This is what I could help with.
https://www.lua.org/manual/5.4/manual.html#2.4
Lua Metatables

this post took me 2 days searching and learning so i can help others :relaxed:

did you learn something?

  • yes
  • no

0 voters

note: I don’t know how to explain it well, but I saw that many people suffer from this problem, so I used it some ai for description

12 Likes

wow that helped me so much ,ty man

2 Likes

Ty so much for the tutorial u took a lot of time to do that this is insane :star:

1 Like

Don’t forget about __call, which is called when you do a() or for i,v in a do end. Or __namecall, which is called when you do a:b(). I am uncertain the type for __namecall, I don’t think it accepts any inputs but I could be wrong.

type __call = <V, A..., B...>(t: V, ...A) -> (B...)

Also, you should probably mention the order index and newindex take and further explain them.

For example, you can enforce newindex by doing:

local b = {}
local a = setmetatable({}, {
	__index = b,
	__newindex = function(a,b,c)
		-- DON'T rawset, recommended to use a proxy (another variable or store in the __index table) if you want to force this to run
	end
})

due to how newindex operates.
Also index chaining exists:

local c = {}
local b = {}
local a = setmetatable({},{
	__index = setmetatable(b, {
		__index = c
	})
})

Index Order: It’ll go {} → b → c when attempting to index, and you can have the final be a function, or use a function to index another table with an index chain or just leave it as a table.

1 Like