Overload Module | Overloaded functions in Lua

What is function overloading?

Explanation

Here’s an example from Java, a language that provides function overloading:

public class Addition {
    // Addition of two integers
    public int add(int a, int b) {
        return a + b;
    }

    // Addition of two strings
    public String add(String a, String b) {
        return a + b;
    }
}
public static void main(String[] args) {
    Addition addition = new Addition();
    int addedInts = addition.add(3, 4); // addedInts = 7
    String addedStrings = addition.add("My ", "String!"); // addedStrings = My String!
}

Many other programming languages have support for function overloading such as C#, C++, Swift, and Kotlin. Interestingly enough you can actually see function overloading in Roblox by typing out CFrame.new().

image

You’ll have 6 different CFrame constructors to choose from. This is an example of overloading.

Overload Module Examples

Add Example

Here’s an example creating an overloaded function allowing you to add both strings and numbers

local add = Overload.new()

add:overload({'number', 'number'}, function(a: number, b: number)
	return a + b
end)

add:overload({'string', 'string'}, function(a: string, b: string)
	return a .. ' ' .. b
end)

print(add(3, 5)) --> Outputs: 8
print(add('Hello', 'world')) --> Outputs: Hello world
XFrame Example

Here’s an example replicating the first four constructors of CFrame.new()

local XFrame = {}
XFrame.new = Overload.new()

XFrame.new:overload({}, function()
	return CFrame.new()
end)
XFrame.new:overload({'Vector3'}, function(pos: Vector3)
	return CFrame.new(pos)
end)
XFrame.new:overload({'Vector3', 'Vector3'}, function(pos: Vector3, lookAt: Vector3)
	return CFrame.new(pos, lookAt)
end)
XFrame.new:overload({'number', 'number', 'number'}, function(x: number, y: number, z: number)
	return CFrame.new(x, y, z)
end)

XFrame.new()
XFrame.new(Vector3.new(3, 4, 5))
XFrame.new(Vector3.new(1, 2, 3), Vector3.new(0, 100, 0))
XFrame.new(8, 9, 10)

API

  • Overload.new(): Overloadable
    • Creates a new Overloadable
  • :overload(types: {[number]: any}, func: function): void
    • Adds a new function to an Overloadable
Source
--[[
	Overload by AstrealDev
	Overloaded functions in Lua
	
	------------------------------------------------------------------------------

	local add = Overload.new()

	add:overload({'number', 'number'}, function(a: number, b: number)
		return a + b
	end)

	add:overload({'string', 'string'}, function(a: string, b: string)
		return a .. ' ' .. b
	end)

	print(add(3, 5)) --> Outputs: 8
	print(add('hello', 'world')) --> Outputs: hello world
]]

local Overload = {}
local RESTRICTED_MODE = false -- Forces the use of primitive-only types
local PRIMITIVE_TYPES = {
	'nil',
	'boolean',
	'number',
	'string',
	'function',
	'userdata',
	'thread',
	'table',
}

--[[
	Utility function for comparing tables
]]
function compare(t1: {[number]: any}, t2: {[number]: any}): boolean
	local isEqual = true
	if (#t1 ~= #t2) then
		return false
	end
	for index, value in ipairs(t1) do
		local value2 = t2[index]
		if (value ~= value2) then
			isEqual = false
		end
	end
	return isEqual
end

--[[
	Create a new Overloadable
]]
function Overload.new()
	local self
	self = setmetatable({
		overloads = {},
	}, {
		__index = Overload,
		__call = function(t, ...)
			local args = {...}
			local providedTypes = {}
			
			for index, value in ipairs(args) do
				table.insert(providedTypes, typeof(value))
			end
			
			for _, overload in pairs(self.overloads) do
				if (compare(overload.types, providedTypes)) then
					return overload.callback(...)
				end
			end
			
			error('No overload matching provided types.')
		end,
	})
	
	return self
end

--[[
	Add a new function to overload in an Overloadable
]]
function Overload:overload(types: {[number]: string}, func)
	if (RESTRICTED_MODE) then
		for _, value in ipairs(types) do
			assert(table.find(PRIMITIVE_TYPES, value) ~= nil, value .. ' is not a valid type.')
		end
	end
	
	for _, overload in pairs(self.overloads) do
		if (compare(overload.types, types)) then
			error('Cannot add overload as an overload with the same types already exists.')
		end
	end
	
	table.insert(self.overloads, {
		callback = func,
		types = types
	})
end

return Overload

Download

15 Likes