Jul 28, 2024

lua rich function notation


local myButton = new "TextButton" {
    ["Size"] = UDim2.new(0, 250, 0, 100),
    ["Text"] = "Click me to do something cool",
    ["*MouseButton1Click"] = (function()
        print("Left mouse button clicked!")
    end)
}

The above script might look a bit odd for a Lua function. After all, there are no parentheses or commas used in the new function, yet somehow both a string and table are being passed as arguments to it.

However, this notation only makes use of vanilla Lua features and runs as expected, with no errors... so how does it work?

This has to do with the fact that in Lua you can actually call a function that takes a string or table without parentheses.

Under the hood, two functions are actually being ran; new and the function that new returns. So the following code block produces identical results to the first:

local newButton = new "TextButton"

local myButton = newButton {
    ["Size"] = UDim2.new(0, 250, 0, 100),
    ["Text"] = "Click me to do something cool",
    ["*MouseButton1Click"] = (function()
        print("Left mouse button clicked!")
    end)
}

The source for the new.lua ModuleScript looks a little something like this:

return function(className)
    return function(properties)
        -- ...
    end
end

We can see the definition of the initial function that takes in a ClassName, which returns a second function with the properties table as a parameter.

This was a technique I made use of in my Proton UI library to allow for easily human-readable generation of UI instances in the Roblox platform. I made use of this technique once more, with the onEvent expression...

local btn = new "TextButton" {
    [onEvent "MouseButton1Click"] = function()
      print("Left mouse button clicked!")
    end
}

In reality, "onEvent" is simply a function that appends an asterisk to the string parameter. So, onEvent "foo" is equal to *foo. This lets the Proton compiler know that we want to attach the function *foo to the event foo. It's super readable easy to understand, and it's all written in vanilla Lua!

You can view the full source code of the new function here!