OOP wrapper(create classes and inheritance a bit more easily)

Hey guys, my friend was trying to get back into roblox and didn’t really like the lua way of doing OOP with metatables and __index spaghetti, so I made a wrapper that does it for him.

It’s pretty easy to make and only ~50 lines, but I wanted to open source it here since I think some people could still benefit from it :slight_smile:

It’s useful if you want to do OOP/classes but have no idea what the heck the __index/metatable stuff is or if you simply want a faster way to create them

Here you go

_G.NewClass = function()
	local class = {}
	class.__index = class
	local new = function(...)
		local self
		if class.super then
			self = setmetatable(class.super.new(...),class)
		else
			self = setmetatable({},class)
		end
		if class.Constructor then
			class.Constructor(self,...)
		end
		return self	
	end
		
	local extends = function(self,superclass)
		setmetatable(self,{__index=superclass})
		self.super = superclass
	end
	
	local superupdate = function(self,...)
		if self.super then
			if self.super.Update then
				self.super.Update(self,...)
			else
				warn("No update method for super class!")
			end
		else
			warn("Can't super update, no super class!")
		end
	end
	
	local superdispose = function(self,...)
		if self.super then
			if self.super.Dispose then
				self.super.Dispose(self,...)
			else
				warn("No dispose method for super class!")
			end
		else
			warn("Can't super dispose, no super class!")
		end
	end
	
	class.new = new
	class.New = new
	class.Extends = extends
	class.extends = extends
	class.superupdate = superupdate
	class.SuperUpdate = superupdate
	class.superdispose = superdispose
	class.SuperDispose = superdispose
	
	return class
end

Details

A class can have a Constructor method.

local class = _G.NewClass()
function class:Constructor(...)
    -- do things with arguments ... from class.new()
end
class.new(...)

This just makes it so you can initialize a class without having to manually set the .__index to the class.

If you want a class to inherit methods from another class, simply do class:Extends(superclass)

local NPC = _G.NewClass()
function NPC:Constructor(name)
     print("New NPC Created with name ",name)
     self.Name = name
end
function NPC:DoNPCThing()
    print("Did NPC Thing on ",self.Name)
end
local Human = _G.NewClass()
function Human:Constructor()
     print("New Human Created")
end
function Human:DoHumanThing()
    print("Did Human Thing on ",self.Name)
end
Human:Extends(NPC)

local NewHuman = Human.new("Frank")
NewHuman:DoHumanThing()
NewHuman:DoNPCThing()

New NPC Created with name Frank
New Human Created
Did Human Thing on Frank
Did NPC Thing on Frank

If you want to propagate disposal or update methods to the super class, simply do
self:SuperUpdate() or self:SuperDispose()

local NPC = _G.NewClass()
local Human = _G.NewClass()
Human:Extends(NPC)

function NPC:Constructor()
	
end
function NPC:Update(deltaTime)
	print("NPC Updated")
	-- Update NPC stuff!
end
function Human:Constructor()
	
end
function Human:Update(deltaTime)
	self:SuperUpdate(deltaTime)
	
	-- Update human stuff!
end

local NewHuman = Human.new()
NewHuman:Update()

NPC Updated

36 Likes

Fixed an issue where subclass.new(…) wouldn’t call superclass.new(…)
(and thus wouldn’t call superclass.Constructor)

1 Like

This is so useful and would make my workflow so much faster. Thanks so much!

1 Like

My only critique is using _G
Aren’t modules a better alternative?
I remember posting about something that used _G once and I got a lot of backlash for it.

I rarely use _G or shared and am not too aware of the penalties of doing so if any exist, but in this case I do it for ease of use. Having to require it every time you want to use it , being that you may be using it in every single module you make, seemed a bit silly to me.

2 Likes

I think the main reason I got backlash was because you’d have to do something like

repeat wait() until _G.NewClass

and that’s a very arbitrary way of waiting for something to load.

Not if you just declare it before your main module loader/main script

In my case I just put it at the top of my main client loader before I require other modules/dependencies

4 Likes