Strictly typed <<Object Oriented Programming>> (Better than metatable OOP)

Object Oriented Programming (Better than metatable OOP)

Tutorial difficulty: Advanced Begginer (no clue what does it mean)

This tutorial will be a mid-short summary about OOP method from: Tower - Roblox

Benefits:

  • More begginer friendly than metatable OOP.

  • faster than metatable OOP by like 10-100% (up to 2 times faster) (Results vary).

  • Easier to write types and don’t require any casting since it uses static types unlike metatable OOP.

  • More customization with metamethods (incase you need them).

  • Can contain multiple classes.

  • Ability to have same constructor for most of your classes.

  • Uses generic tables that don’t require any deep copy.

Cons:

  • No dirrect support from Roblox like with metatable OOP (as for now and i hope that it will change)

In this tutorial we will learn:

  • how to create a constructor
  • how to add methods to constructor
  • how to make a generic table
  • how to create types and assign them to our generic table/constructor/method

For more advanced tutorial i would recomend you watching my video on this OOP approach:

Before doing anything lets set us a goals:

  • Make a class Cat.
  • Give class cat ability to print “Meow” via method “Meow”.
  • Method that would print Text we input aswell as adding subtag with name of our cat in beggining of the message.
  • Make class Cat include: Age of this cat and Name of this cat.
  • Method that would tell us name and age of our class cat.

Part 1: Writing a Generic table

local Cat = {
Name="";
Age=0;
}

Part 2: Writing a constructor:

-- self shall be ignored as since calling methods will automatically pass 1st argument
--Source: https://create.roblox.com/docs/luau/functions#define-methods

function Constructor(self,Name,Age)
-- nelf is our newly created class!
local nelf = table.create(self)

-- will cast Name to string
nelf.Name = `{Name}`
-- will cast Age to number and if will fail then age will be 0
nelf.Age = tonumber(Age) or 0
-- returning our class
return nelf
}

local Cat = {
-- Referance to our constructor
new = Constructor;

Name="";
Age=0;
}

Part 3: Adding methods

-- self shall be ignored as since calling methods will automatically pass 1st argument
--Source: https://create.roblox.com/docs/luau/functions#define-methods

function Constructor(self,Name,Age)
-- nelf is our newly created class!
local nelf = table.create(self)

-- will cast Name to string
nelf.Name = `{Name}`
-- will cast Age to number and if will fail then age will be 0
nelf.Age = tonumber(Age) or 0
-- returning our class
return nelf
end

--Just a function, not an actual method 
function Meow()
 warn("Meow")
end
-- Upon calling it will say Name of our cat + text
function Say(self,text)
 warn(`{self.Name}: {text}`)
end
function Info(self)
 return self.Name,self.Age
end

local Cat = {
-- Referance to our constructor
new = Constructor;
-- Referance to function (could be used without : but . instead when calling)
Meow = Meow;

Say = Say;
Info = Info;

Name="";
Age=0;
}

Part 4: Adding types and description

--!strict
--!optimize 2
-- self shall be ignored as since calling methods will automatically pass 1st argument
--Source: https://create.roblox.com/docs/luau/functions#define-methods

--[[
if you see argument <strong>self</strong> after writing then you are doing smth wrong; Perhabs you used singular dot instead of : for method calling
<strong>Name</strong> Name of our cat
<strong>Age</strong> Age of our cat
]]
function Constructor(self:Cat,Name:string,Age:number): Cat
	-- nelf is our newly created class!
	local nelf = table.clone(self)

	nelf.Name = Name
	nelf.Age = Age
	-- returning our class
	return nelf
end

--Just a function, not an actual method 
--[[
Can be called with singular dot aswell
A void function
]]
function Meow(): ()
	warn("Meow")
end
-- Upon calling it will say Name of our cat + text
function Say(self:Cat,text:string): ()
	warn(`{self.Name}: {text}`)
end
--[[Returns <strong>Tuple</strong> type that contains Name and Age of our cat]]
function Info(self:Cat): (string,number)
	return self.Name,self.Age
end

local Cat:Cat = {
	-- Referance to our constructor
	new = Constructor;
	-- Referance to function (could be used without : but . instead when calling)
	Meow = Meow;

	Say = Say;
	Info = Info;

	Name="";
	Age=0;
}

-- Creating type for our cat
export type Cat = {
-- Methods
	-- typeof does get what does function returns and description of function incase it has one
	new:typeof(Constructor);
	Meow:typeof(Meow);
	Say:typeof(Say);
	Info:typeof(Info);
-- Properties
	Name:string;
	Age:number;
}

Part 5: Usage

--!strict
--!optimize 2
-- self shall be ignored as since calling methods will automatically pass 1st argument
--Source: https://create.roblox.com/docs/luau/functions#define-methods

--[[
if you see argument <strong>self</strong> after writing then you are doing smth wrong; Perhabs you used singular dot instead of : for method calling
<strong>Name</strong> Name of our cat
<strong>Age</strong> Age of our cat
]]
function Constructor(self:Cat,Name:string,Age:number): Cat
	-- nelf is our newly created class!
	local nelf = table.clone(self)

	nelf.Name = Name
	nelf.Age = Age
	-- returning our class
	return nelf
end

--Just a function, not an actual method 
--[[
Can be called with singular dot aswell
A void function
]]
function Meow(): ()
	warn("Meow")
end
-- Upon calling it will say Name of our cat + text
function Say(self:Cat,text:string): ()
	warn(`{self.Name}: {text}`)
end
--[[Returns <strong>Tuple</strong> type that contains Name and Age of our cat]]
function Info(self:Cat): (string,number)
	return self.Name,self.Age
end

local Cat:Cat = {
	-- Referance to our constructor
	new = Constructor;
	-- Referance to function (could be used without : but . instead when calling)
	Meow = Meow;

	Say = Say;
	Info = Info;

	Name="";
	Age=0;
}

-- Creating type for our cat
export type Cat = {
-- Methods
	-- typeof does get what does function returns and description of function incase it has one
	new:typeof(Constructor);
	Meow:typeof(Meow);
	Say:typeof(Say);
	Info:typeof(Info);
-- Properties
	Name:string;
	Age:number;
}

local ClassCat1 = Cat:new("Tiger",3)
ClassCat1.Meow()
ClassCat1:Say("Im a talking cat")
local Name,Age = ClassCat1:Info()
print(`Info: Age: {Age}, Name: {Name}`)

That whole tutorial.

You could do a lot of work arounds with this OOP method but i like this exact way of it becouse it keeps polymorphy just enough.
This is my first tutorial of that kind and i would like to hear suggestions as to how i can improve my future/this tutorial(s).

2 Likes