Luau Function Overloading

As a Roblox developer, it is currently too hard to create multiple functions that take unique type signatures with the same name.

If Roblox is able to address this issue, it would improve my development experience, because I would be able to make simpler modules, functions, scripts, etc.


Egregious Example

As we all know, most of the functions we use (CFrame.new(6 methods), ColorSequence.new(3 methods), etc.), has multiple methods of constructing a value:

image

image

When constructing a CFrame, we can choose to have either:

  • Empty, just a 0, 0, 0 CFrame
  • 1 Vector3 (position)
  • 3 numbers as a Vector3 position
  • 2 Vector3 (position, lookAt)
  • 5th method I don’t really understand (Probably something to do with position and rotation)
  • A method to construct a CFrame with all the “matrixes”

Now, what I suggest, is to add a feature, where you can make a constructor that takes unique combinations of arguments, as multiple methods. Basically, function overloading.

function foobar(a: number, b: Vector3): string
    return "I got a number and a Vector3!"
end

-- As of now, this just prints an error, telling us that we overwrote a function.
function foobar(a: Vector3): string
    return "I got a Vector3!"
end

function foobar(a: nil): string
    return "I got nothing. :("
end

print(foobar(Vector3.new(5, 15, 7))) -- "I got a Vector3!"
print(foobar(7, Vector3.new(62, 13, 5))) -- "I got a number and a Vector3!"
print(foobar()) -- "I got nothing. :("

This is in fact possible with a normal function, but this isn’t very feasible to do so.

function foobar(a, b)
    if typeof(a) == "number" and typeof(b) == "Vector3" then
        return "I got a number and a Vector3!"
    elseif typeof(a) == "Vector3" then
        return "I got a Vector3!"
    end
    return "I got nothing. :("
end

print(foobar(Vector3.new(5, 15, 7))) -- "I got a Vector3!"
print(foobar(7, Vector3.new(62, 13, 5))) -- "I got a number and a Vector3!"
print(foobar()) -- "I got nothing. :("

Module Example
local module = {}

function module:GetSomething(a: Vector3): Vector3
    return a * Vector3.new(5, 2, 1.5)
end

function module:GetSomething(a: number): string
    return "Your number is " .. tostring(a) .. "."
end

function module:GetSomething(a: nil): string
    return "I think you forgot to insert an argument..."
end

return module

Use cases:

  • Simpler, yet more effective modules
  • Easier organization in scripting

Here’s a wiki page more about function overloading.

9 Likes

The issue here is that everything in Lua is treated like an object, even functions. This might cause a lot of confusion and unintentional behavior as Lua stores only one object per variable, while your suggestion means storing multiple functions in one.

I feel like overloading should be part of the initial function declaration, explicitly showing that it is done on the object, not the variable.

function foobar (a:number)
    print("nubmer",a)
overload (a:string)
    print("string",a)
end

Obviously it seems weird, but less so than your example.

One problem is that declaring a function over a variable is already valid

local function f(a:number)
    return a*2
end
function f(a:string)
    return a..a
end
function f(a:boolean)
    return not a
end

Would this use the new overload system or would it continue to function the same?

Would overload be a keyword?
It would be difficult if not impossible to disambiguate this if it wasn’t

type t = {f:number,typeof:(t,string) -> any}
local s = "abc"
local overload = print
local function f(a:t)
    do return a.f end
overload(a:typeof(s))
    do return a..s end
end

Would this be an overload or would this call overload with all results of calling method typeof on a with arguments s (like how it is currently)?

Function overloading is a good way to confuse yourself; I don’t personally want it.

The example you listed, CFrame.new, is a particularly egregious one. It’s impossible to know what it’s doing at a glance. What does CFrame.new(x, y, z) do? You have to go check where these variables are defined to be able to know.

My main point was to avoid declaring a function twice, as them still keeping the previous behavior is very confusing.

What I find weird is what would happen if you were to set the overloaded function as a table’s value. How would that even work? Most languages that have overloading restrict it to class methods; meanwhile, here we have a new function being created which doesn’t actually create a new object, but extends an existing one. Yet, creating a function without overloading does create a new object.

overload would be a keyword and my main reasoning behind this was the same as else/elseif in case of if statements.

I agree that function overloading should be supported with luau, especially given what we can do with it.

This is used rather often in OOP languages, and seeing as people like OOP in Roblox (it has its benefits, but should not be defaulted to in all cases), this would totally improve OOP as a whole. We could extend classes, setup certain methods as “do nothing” methods until they are finally edited by the class extending the initial class… and so on.

Also, given what we can currently do with luau, I fully support this.

2 Likes