Custom Functions/Events

Hi there,
So I have finally started learning about metatables and its usage.
Tho,
I was wondering,

How would I acheive something like this-

Which basically should return me a table of only basepart class items in workspace.
I know I could use “IsA”, but I want a fresh & more advanced way.

local Bricks = Workspace:GetOnlyBaseParts()

--Or even better:
local Target = Workspace:GetItemsOfClass(ClassName)

Or even something cool like this-

local ItemsToRemove = Workspace:GetPartsToRemove(classname,name(optional))

Or even:

local Parts = Workspace:GetPartsOfClass(classname)

local PaintParts = Parts:Paint(Color3)
1 Like

How could I make something like those?

Custom functions are really vast and nice, & an opportunity to let us be creative a bit and do some stuff

1 Like

You can use a wrapper.

2 Likes

What is a wrapper? I am new to this topic
I understood how to make simple custom functions such as ‘VanishObject’,

But how could I make a function that returns a table?(custom function)

Assuming you know of the __index and __newindex metamethods, you can use it to return the instance instead of a table.

local realWorkspace = workspace
local workspace = {}
workspace.__index = realWorkspace

function workspace:PrintHi()
    print('hi')
end

function workspace.new()
    local newWorkspace = {}
    -- inside the newWorkspace table, you add your properties and events, not functions
    return setmetatable(newWorkspace, workspace)
end

Everything is explained well in the tutorial so you should check that out. You’ll notice you won’t be able to call native workspace methods natively so you can use this:

1 Like

Oh, that’s nice.

So if I wanted to make a custom function that returns me only the given class(name) , for e.g:

local Detect = Workspace:GetOnlyModels()

How would I do that?
(The examples you sent me, talk about simple functions that return instances, not tables

Make a function that iterates through the workspace and adds all of the models to a table then returns it.

Alright, so far I have this

--//Variables
local realWorkspace = workspace
local functions = {}
functions.__index = realWorkspace

--//Functions
function functions:GetItems(class:string)
	local items = {}
	for _,Item in pairs(game.Workspace:GetDescendants()) do
		if Item:IsA(class) then
			table.insert(items,Item)
		end
	end
	return items
end

function functions.new()
	local newFunctions = {}
	return setmetatable(newFunctions, functions)
end

Okay, so you need to now call functions.new(), and with the object returned from that, call :GetItems on it and it should work.

2 Likes
--//Variables
local realWorkspace = workspace
local functions = {}
functions.__index = realWorkspace

--//Functions
function functions:GetItems(class:string)
	local items = {}
	for _,Item in pairs(game.Workspace:GetDescendants()) do
		if Item:IsA(class) then
			table.insert(items,Item)
		end
	end
	return items
end

function functions.new()
	local newFunctions = {}
	return setmetatable(newFunctions, functions)
end


--//logic
local result = functions.new()
result:GetItems("BasePart") 

Gave an error

Oh I see the issue, you will have to make the __index metamethod a function that returns a function inside of functions if it exists, else returns the real instance’s function. So like

local functions = {}
-- class methods go in the functions table

function functions:__index(key)
    if functions[key] then
        return functions[key]
    else
        return workspace[key]
    end
end

function functions.new()
    local object = {}
    -- properties and events here
    return setmetatable(object, functions)
end
--//Variables
local realWorkspace = workspace
local functions = {}
functions.__index = realWorkspace

--//Functions
function functions:GetItems(class:string)
	if functions[class] then
		return functions[class]
	else
		return workspace[class]
	end
end

function functions.new()
	local object = {}
	return setmetatable(object, functions)
end


--//logic
local result = functions.new()
result:GetItems("BasePart") 

error again

This has to be a function that returns functions[index] if functions[index] exists, or workspace[index]

--//Variables
local realWorkspace = workspace
local functions = {}
functions.__index = functions

--//Functions
function functions:GetItems(class:string)
	if functions[class] then
		return functions[class]
	else
		return workspace[class]
	end
end

function functions.new()
	local object = {}
	return setmetatable(object, functions)
end


--//logic
local result = functions.new()
print(table.concat(result:GetItems("BasePart"),","))

it doesnt print

nor does this one -

--//Variables
local realWorkspace = workspace
local functions = {}
functions.__index = functions

--//Functions
function functions:GetItems(class:string)
	local items = {}
	for _,Item in pairs(game.Workspace:GetDescendants()) do
		if Item:IsA(class) then
			table.insert(items,Item)
		end
	end
	return items
end

function functions.new()
	local object = {}
	return setmetatable(object, functions)
end


--//logic
local result = functions.new()
print(table.concat(result:GetItems("BasePart"),","))

This still is not a function. It has to be a function that checks if functions[index] exists where index is the second argument passed to the __index function. If it does exist, return functions[index], else return workspace[index]

1 Like

Well, that’s a huge confusion right here…
Never thought it’d be that confusing & difficult to understand that…

Yeah, object wrappers are difficult to understand but one day it just clicked for me so I’ll try explaining it as best as I can. So, __index is a metamethod that can either be a function or another object.

If it is a function it will call that function, if it is another object, it will look in this other object for the index

1- newObject = object.new() - newObject is a table that contains properties/events, and whose metatable has a __index metamethod that is a function.
2- newObject.nonexistentkey - Since no entry in newObject exists with the index nonexistentkey, it gets the __index metamethod of the newObject object, and calls that __index metamethod if object.nonexistentkey does not exist. In our case it does not exist, so it passes the table that was attempted to be indexed as the first argument (in our case it’s newObject) and as the second argument it’s the key that was used to attempt to index newObject. We do not need to call __index with parentheses because indexing newObject with a nonexistent key calls this already.
3- In our __index function, we attempt to index functions, which is the table with class methods that extend the actual workspace methods, with nonexistentkey. This does not invoke any metamethods. If it exists return it.
4- nonexistentkey does not exist in the functions table, so we index the real instance with nonexistentkey, this will either error properly, or returns the real instance property.

In the end, imagine it like this,
This line:
local myProperty = newObject.nonexistentkey
Is the same same as doing

local myProperty = getmetatable(newObject).__index(newObject, 'nonexistentkey')

So, in the end, the process is like this, where you attempt each step and if one of the steps is successful, use the result from the successful attempt, if it errors, do nothing, if nil is returned but it did not error, proceed:
1- look in newObject for nonexistentkey
2- look in newObject’s metatable for nonexistentkey
3- look in realWorkspace for nonexistentkey
4- no options left, return nil.

2 Likes

Hey again,

So I watched AlvinBlox's tutorial on metatables, and now I understand how to use __index and __newindex .

But unfortunately, I still am confused how would I use these in my case?

Put the metamethods in your functions table, then use the functions table as your metatable.

function functions:__index(key)
    if functions[key] then
        return functions[key]
    else
        return workspace[key]
    end
end
--...
return setmetatable(newTable, functions)

This function is defined as a metamethod, it confuses me

Why isnt it defined with a name? (Like regular funtions), will there be a difference if I were to name it function functions:Test(key)