How to make multi-argument choose function in LuaU?

104 Views Asked by At

I want to make function which returns multiple variants "how to use function": var.get(a:number): any next is var.get(a:string,b:number): any next is var.get(): any.

I know by Roblox Lua (LuaU) it's possible and it returns as pages like I did upper. How can I make same? (please provide code) I'm sure it should be one function but how it returns multiple variants of how to use it?

I tried:

local var={}
function var.get(a:number):any
  -- some code here
end
function var.get():any
  -- some code here
end

But it didn't worked.

2

There are 2 best solutions below

1
Alexander Mashin On BEST ANSWER

As @Kylaaa said, there is no function overloading in Lua out of the box. But Lua is flexible, and function overloading can be emulated, using already mentioned variadic functions and the fact that, in Lua, functons are first-class objects.

local function overloaded (signatures)
    local concat = table.concat

    -- Serialise signatures beforehand to compare them as strings at call time:
    local serialised_signatures, fallback = {}, nil
    for signature, implementation in pairs (signatures) do
        if type (signature) == 'number' or signature == 'void' then
            -- syntactic sugar for an empty signature:
            signature = ''
        elseif type (signature) == 'table' then
            -- long signatures:
            signature = concat (signature, ', ')
        elseif signature == '...' then
            -- fallback: any unrecognised signature:
            fallback = implementation
        end -- otherwise, it is a signature with one argument, which remains a string.
        serialised_signatures [signature] = implementation
    end
            
    -- Get the serialised signature of a function call at runtime:
    local function arg_types (...)
        local types = {}
        for i, arg in ipairs {...} do
            types [i] = type (arg)
        end
        return concat (types, ', ') -- to make comparing easier.
    end
    
    return function (...)
        local called_with_args = arg_types (...)
        for signature, implementation in pairs (serialised_signatures) do
            if called_with_args == signature then
                return implementation (...)
            end
        end
        -- fallback:
        return fallback (...)
    end
end

local get = overloaded {
    -- no arguments. [{}], or [''], or void index will have the same effect:
    function ()
        return 'If you want to get something, give something'
    end,
    -- one argument, number:
    number = function (number)
        return 'You have given the number ' .. number
    end,
    -- one argument, string, but passed as a list:
    [{ 'string' }] = function (string)
        return 'You have given the string "' .. string .. '"'
    end,
    -- several arguments:
    [{ 'number', 'number' }] = function (no1, no2)
        return 'You have given two numbers: ' .. no1 .. ' and ' .. no2
    end,
    -- any other signature:
    ['...'] = function (...)
        return 'The supplied arguments were: ' .. table.concat ({...}, ', ')
    end
}

print ('get () = ' .. get ())
print ('get (42) = ' .. get (42))
print ("get 'fourty-two' = " .. get 'fourty-two')
print ('get (4, 2) = ' .. get (4, 2))
print ("get (1, 'some string') = " .. get (1, 'some string'))
0
Kylaaa On

The technical term for what you're trying to do is called "function overloading". And currently it's not possible in Lua or Luau. An engine feature request was made for it back in 2020, but that didn't get much traction.

You cannot have multiple functions with the same name with different signatures. In your example, think of the table var as as a collection of buckets. When you define the get(a:number):any function, you put it into the bucket named get. The next time you try to define get():any, you empty out the bucket named get and replace it with the new function. You can only have one thing in each bucket, or more technically, you can only have one value defined on any key in a table.

However, if you want to achieve something like function overloading, vanilla Lua does allow you to call a function with any number of arguments. This is called a variadic function, they are very useful and Luau supports them too.

local var = {}
function var.get(...):any
    local args = {...} -- store all the extra arguments in an array
    --print(...) -- print out the arguments provided to get

    -- figure out how people have called this function
    if #args == 0 then -- called as get()
        print("get() called with no arguments!")
    else if #args == 1 then
        print("get() called with one argument : ", args[1])
    else
        print("get() called with many arguments : ", ...)
    end

    return args
end

-- allows you to use it like...
var.get()
var.get("hello")
var.get("this", "is", "a", "test", 123, false)

Personally, I wouldn't recommend doing it this way. The flexibility to call your function any way you want doesn't justify the amount of headache needed to make this work. It is cleaner to simply create multiple functions for the different signatures.

local var = {}
function var.get()
    print("get()")
end
function var.getOne(n : number)
    print("getOne", n)
end
function var.getTwo(n : number, s : string)
    print("getTwo", n, s)
end