Class++ [Beta v1.4] | Classes and OOP made easy and powerful with Access Specifiers, function overloading and more!


And here’s an image of a benchmarking test I’ve ran.
(Note: "Class++ Native & Strict is an older version of Class++, the performance is even better now with further optimizations)

You got me so excited! :sob:, I thought “Theres no way he figured out how to make the custom classes have types!”

image

I don’t know if such a feature would even be possible. typeof(setmetatable({}, T))?
But congrats! this resource is really interesting!

1 Like

Do you mean automatic typechecking for the class members? Trust me, I really tried. I don’t think it’s possible. Especially in this system where the classData properties are being transferred through several functions.

Though you have one solution: Since objects belong to the base type userdata, you can easily cast a custom type to them, and they will work perfectly fine!

Also, thank you!

1 Like

Updated the links to include creator store!

Is this for object oriented programming?

Yes, this module aims to make OOP much easier for new and old developers!
I’m open to feedback by the way, make sure to send feature requests and bug reports if you have any!

Release 1.1.0


  • Improved performance while creating new objects, it should be quite faster to create them now.
  • Other performance improvements.
  • Added more comments and explanations on how certain functions work, and added support for an upcoming Studio documentation feature.

A performance comparison picture between 1.0.0 and 1.1.0:

Also I added a new creator store link to make getting the module easier, make sure to check it out!

1 Like

Updated the documentation with some new features and fixes, and updated the main post with a comparision.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ClassPP = require(ReplicatedStorage["Class++"])
local class = ClassPP.class

local Car = class "Car" {
    Public = {
        Brand = "Lamborghini",
    },
    Private = {
        License_Plate = "XXXX"
    },
    changeLicensePlate = function(self, plate:string)
        self.License_Plate = plate
        return self
    end,
}

local newCar = Car.new()
newCar:changeLicensePlatw(“YYYY”)

can i do it like this?

Oh no, that would give an invalid access specifier error. Members must always be placed inside access specifiers. Try putting the function inside an access specifier, for example, Public like below:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ClassPP = require(ReplicatedStorage["Class++"])
local class = ClassPP.class

local Car = class "Car" {
    Public = {
        Brand = "Lamborghini",
        changeLicensePlate = function(self, plate: string) -- We put this function inside the Public Access Specifier, so it can be accessible from everywhere.
           self.License_Plate = plate
        end,
    },
    Private = {
        License_Plate = "XXXX"
    },
}

local newCar = Car.new()
newCar:changeLicensePlate("YYYY")

Check out the documentation for more information access specifiers! You should read the entire thing through, it would be very useful.

Release Beta 1.2.0


  • Improved performance on accessing an object’s Private and Protected access specifiers.
  • Updated the final and abstract functions to now accept multiple classes with a new syntax.
  • Util.inClassScope function now accepts a new optional defaultLevel value that determines the default call stack level the function will start doing the checks on.

A performance comparison picture between 1.1.0 and 1.2.0:

1 Like

Release Beta 1.3.0


  • Improved performance when creating and accessing an object.
  • Updated the API Reference and Tutorial documentation to include a new feature: static members.

Introducing a new function:

class.static(accessSpecifier: string, name: string, property: any)
  • Classes can now have static members using this function, just like in Java and C++, they belong to the class, and will not replicate to the objects created from the class.
  • They’re global, and will be the same everywhere.
  • You can access the static members through the class object like:
    class.<memberName>.property or class.<memberName>.p for short.

Check out the documentation for more info!

Release Beta 1.3.1


  • Fixed cyclic tables causing stack overflow when the object is getting destroyed.
  • Fixed when a member is set to false, that member is no longer indexable.
  • Performance improvements.

Make sure to get the latest version to get the most amount of performance, and fixes!

I have put a tool into the .new() function and constructor function, its says This class has no member named “Tool”.

Can you send the script here so I can take a look?

Forgot to include, I’ve updated the API Reference a little bit to show the properties in a better style.

This is the script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")

local ClassPP = require(ReplicatedStorage["Class++"])
local class = ClassPP.class


local toolClass = class "Tool" {
	
	constructor = function(self, tool)
		
		if tool and tool:IsA("Tool") then
		
			self.Tool = tool
			self.Configuration = require(self.Tool.Config) 

			self.Tool.Equipped:Connect(function()
				
				self.equipped = true
			end)
			self.Tool.Unequipped:Connect(function()
				
				self.equipped = false
			end)
		end
	end,
	Public = {
		equipped = false,
		Tool = nil,
		Configuration = {},
	}
}

CollectionService:GetInstanceAddedSignal("Tool"):Connect(function(tool)
		
	if tool:IsA("Tool") then
		
		local newTool = toolClass.new(tool)
	end
end)

This is the Error : {Class++}: This class has no member named "Tool".

I see what you mean now, this is a common mistake that people encounter when creating classes using my module.

This is mostly related on how dictionaries work in Luau, when you set a key to nil, you’re actually removing that key from the table. In this case, the key Tool is being set to nil in the Public access specifier, and since you’re setting the key Tool to nil, Lua automatically removes it from the table, which in the final classData, the Tool member does not exist.

To solve this issue, instead of setting it to nil, you can set it to false.
Here’s your updated code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")

local ClassPP = require(ReplicatedStorage["Class++"])
local class = ClassPP.class


local toolClass = class "Tool" {
	
	constructor = function(self, tool)
		if tool and tool:IsA("Tool") then
			self.Tool = tool
			self.Configuration = require(tool.Config) 

			self.Tool.Equipped:Connect(function()
				self.equipped = true
			end)

			self.Tool.Unequipped:Connect(function()
				self.equipped = false
			end)
		end
	end,
	Public = {
		equipped = false,
		Tool = false,
		Configuration = {},
	}
}
1 Like

Oh man i didnt know this about dictionaries, thank you. :smiley:

1 Like

Release Beta 1.4.0


  • Performance improvements.
  • Fixed some bugs.
  • Updated the final method to support functions with the syntax below:
local class, final = ClassPP.class, ClassPP.final

local Test = class "Test" {
	Public = {
		test = final(function(self, ...) 
			print(self, ...)
		end),
	}	
}

A performance comparison picture between 1.3.1 and 1.4.0:

1 Like