BindableFunction

Show Deprecated

An object that allows you to give access to functions to external scripts. Functions put in BindableFunctions will not be replicated, therefore making it impossible to use these objects to pass functions between scripts. Functions are invoked through BindableFunction:Invoke(), which calls BindableFunction.OnInvoke.

BindableFunctions do not allow for communication between the server and client. If you are looking for this functionality use RemoteFunctions.

BindableEvents vs BindableFunctions

Unlike BindableFunctions, BindableEvents only allow for one-way communication between two scripts:

  • When a script invokes a BindableFunction it yields until the event is handled and returned by the subscribed script synchronously. This allows for scripts to effectively pass data during and after an event.
  • When a script fires a BindableEvent, however, it does not yield for a return. The script continues executing as the event is handled by the subscribed script asynchronously.

BindableFunctions vs RemoteFunctions

While BindableFunctions allow for two-way communication server-server scripts or client-client LocalScripts, RemoteFunctions allow for two-way communicate the server and client. For more information on RemoteFunctions, see Remote Events and Functions.

Limitations

Invocations will yield until the corresponding callback is found. If the callback was never set, the script that invokes it will not resume execution.

Subscription

Only one function can be bound to BindableFunction:Invoke() at a time. If you assign multiple functions, only the last one assigned will be used.

Parameter Limitations

Any type of Roblox object such as an Enum, Instance, or userdata can be passed as a parameter when a RemoteEvent is fired or a RemoteFunction invoked. Lua types such as numbers, strings, and booleans can also be passed, although there are some limitations on how data can be passed.

Table Identity

Copies of tables are produced when passed as arguments to or returned from the OnInvoke callback. This means that means that tables passed as arguments will not be exactly equivalent to those provided on invocation, and tables returned to the invoker will not be exactly equivalent to the ones returned by the OnInvoke callback. You can demonstrate this by running the following script in a BindableFunction:


local bindableFunction = script.Parent
bindableFunction.OnInvoke = function (t)
print("OnInvoke", tostring(t), t)
t = {bar = "foo"}
print("OnInvoke2", tostring(t), t)
return t
end
local t = {foo = "bar"}
print("Subscriber", tostring(t), t)
local retVal = script.Parent:Invoke(t)
print("return", tostring(retVal), retVal)

The above code may produce the following results in the output. Notice how the memory addresses of every table printed are completely different from each other, indicating they each represent different tables:


13:55:22.228 Subscriber table: 0xc7daaba4d5307f10 ▶ {...} - Publisher:11
13:55:22.229 OnInvoke table: 0x2ee92a7818e7d210 ▶ {...} - Publisher:4
13:55:22.229 OnInvoke2 table: 0xfa4ee529ddadf290 ▶ {...} - Publisher:6
13:55:22.229 return table: 0x35b7bc1bc323d510 ▶ {...} - Publisher:13

Mixed Tables

Avoid passing a mixed table (some values indexed by number and others by key), as only the data indexed by number will be passed. For example, when the server receives the colorData table illustrated below, it only sees indices 1 and 2 containing "Blue" and "Yellow" while the other data is lost in the transfer. Note, however, that sub-tables do not need to be indexed in the same way as their parent — in other words, as long as each individual sub-table is indexed with the same type, all of the data is preserved.

Metatables are not preserved.

Non-String Indices

If any indices of a passed table are non-string type (Instance, userdata, function, another table, etc.), those indices will be converted to a string.


-- Mixed table
local colorData = {}
colorData[1] = "Blue"
colorData[2] = "Yellow"
colorData["Color1"] = "Green"
colorData["Color2"] = "Red"
-- Table with two key-indexed sub-tables
local playerData = {}
playerData["CharData"] = {
-- All children indexed by key
CharName = "Diva Dragonslayer",
CharClass = "Knight"
}
playerData["Inventory"] = {
-- All children numerically indexed
"Sword",
"Bow",
"Rope"
}

Functions

Functions passed as parameters will not be replicated, therefore making it impossible to use these objects to pass functions between scripts.

Code Samples

BindableFunction Addition

local bindableFunction = script.Parent
-- Define a function for use with the BindableFunction
local function AddTwoNumbers(a, b)
return a + b
end
-- Set the OnInvoke callback to be our function
bindableFunction.OnInvoke = AddTwoNumbers
-- Invoke the BindableFunction
print(bindableFunction:Invoke(25, 44))
BindableFunction Valid Values

local bindableFunction = script.Parent
-- Dummy function
bindableFunction.OnInvoke = function(...)
return ...
end
-- These values CAN be sent to/from BindableFunctions
bindableFunction:Invoke() -- nil
bindableFunction:Invoke(25) -- numbers
bindableFunction:Invoke("hello") -- strings
bindableFunction:Invoke(true) -- booleans
bindableFunction:Invoke("buy", 25) -- multiple values are OK
bindableFunction:Invoke({ 1, 2, 3 }) -- tables as arrays with no gaps
-- note the curly braces
bindableFunction:Invoke({ -- tables with string keys only
hello = "world",
goodbye = "world",
})
bindableFunction:Invoke({ -- tables with string keys
point = { 1, 2 }, -- whose values are also valid
point2 = { 3, 4 },
})
bindableFunction:Invoke({ -- tables as arrays
{ 1, 2, 3 }, -- whose values also are valid
{ hello = "world" },
})
-- These are some values you CANNOT send to/from BindableFunctions
bindableFunction:Invoke({ 1, nil, 3 }) -- tables as arrays cannot have nil gaps
bindableFunction:Invoke({
[{}] = "hello", -- table keys can only be numbers OR strings
})
bindableFunction:Invoke({ -- tables keys cannot be BOTH numbers AND strings
[1] = "apple",
hello = "world",
})

Summary

Properties

Methods

Invoke(arguments: Tuple): Tuple  YIELDS

Calls the BindableFunction.OnInvoke callback of the BindableFunction, returning any values returned by the callback.

Events

Callbacks

OnInvoke(arguments: Tuple)  

Properties

Methods

Invoke

Yields

Calls the BindableFunction.OnInvoke callback and returns any values that were returned by the callback.

Limitations

Invocations will yield until the corresponding callback is found. If the callback was never set, the script that invokes it will not resume execution.

Subscription

Only one function can be bound to BindableFunction:Invoke() at a time. If you assign multiple functions, only the last one assigned will be used.

Parameter Limitations

Any type of Roblox object such as an Enum, Instance, or userdata can be passed as a parameter when a RemoteEvent is fired or a RemoteFunction invoked. Lua types such as numbers, strings, and booleans can also be passed, although there are some limitations on how data can be passed.

Table Identity

Copies of tables are produced when passed as arguments to or returned from the OnInvoke callback. This means that means that tables passed as arguments will not be exactly equivalent to those provided on invocation, and tables returned to the invoker will not be exactly equivalent to the ones returned by the OnInvoke callback. You can demonstrate this by running the following script in a BindableFunction:


local bindableFunction = script.Parent
bindableFunction.OnInvoke = function (t)
print("OnInvoke", tostring(t), t)
t = {bar = "foo"}
print("OnInvoke2", tostring(t), t)
return t
end
local t = {foo = "bar"}
print("Subscriber", tostring(t), t)
local retVal = script.Parent:Invoke(t)
print("return", tostring(retVal), retVal)

The above code may produce the following results in the output. Notice how the memory addresses of every table printed are completely different from each other, indicating they each represent different tables:


13:55:22.228 Subscriber table: 0xc7daaba4d5307f10 ▶ {...} - Publisher:11
13:55:22.229 OnInvoke table: 0x2ee92a7818e7d210 ▶ {...} - Publisher:4
13:55:22.229 OnInvoke2 table: 0xfa4ee529ddadf290 ▶ {...} - Publisher:6
13:55:22.229 return table: 0x35b7bc1bc323d510 ▶ {...} - Publisher:13

Mixed Tables

Avoid passing a mixed table (some values indexed by number and others by key), as only the data indexed by number will be passed. For example, when the server receives the colorData table illustrated below, it only sees indices 1 and 2 containing "Blue" and "Yellow" while the other data is lost in the transfer. Note, however, that sub-tables do not need to be indexed in the same way as their parent — in other words, as long as each individual sub-table is indexed with the same type, all of the data is preserved.

Metatables are not preserved.

Non-String Indices

If any indices of a passed table are non-string type (Instance, userdata, function, another table, etc.), those indices will be converted to a string.


-- Mixed table
local colorData = {}
colorData[1] = "Blue"
colorData[2] = "Yellow"
colorData["Color1"] = "Green"
colorData["Color2"] = "Red"
-- Table with two key-indexed sub-tables
local playerData = {}
playerData["CharData"] = {
-- All children indexed by key
CharName = "Diva Dragonslayer",
CharClass = "Knight"
}
playerData["Inventory"] = {
-- All children numerically indexed
"Sword",
"Bow",
"Rope"
}

Functions

Functions passed as parameters will not be replicated, therefore making it impossible to use these objects to pass functions between scripts.

Parameters

arguments: Tuple

Values to be passed to the callback.


Returns

Values passed to the callback.

Code Samples

BindableFunction Addition

local bindableFunction = script.Parent
-- Define a function for use with the BindableFunction
local function AddTwoNumbers(a, b)
return a + b
end
-- Set the OnInvoke callback to be our function
bindableFunction.OnInvoke = AddTwoNumbers
-- Invoke the BindableFunction
print(bindableFunction:Invoke(25, 44))
BindableFunction Valid Values

local bindableFunction = script.Parent
-- Dummy function
bindableFunction.OnInvoke = function(...)
return ...
end
-- These values CAN be sent to/from BindableFunctions
bindableFunction:Invoke() -- nil
bindableFunction:Invoke(25) -- numbers
bindableFunction:Invoke("hello") -- strings
bindableFunction:Invoke(true) -- booleans
bindableFunction:Invoke("buy", 25) -- multiple values are OK
bindableFunction:Invoke({ 1, 2, 3 }) -- tables as arrays with no gaps
-- note the curly braces
bindableFunction:Invoke({ -- tables with string keys only
hello = "world",
goodbye = "world",
})
bindableFunction:Invoke({ -- tables with string keys
point = { 1, 2 }, -- whose values are also valid
point2 = { 3, 4 },
})
bindableFunction:Invoke({ -- tables as arrays
{ 1, 2, 3 }, -- whose values also are valid
{ hello = "world" },
})
-- These are some values you CANNOT send to/from BindableFunctions
bindableFunction:Invoke({ 1, nil, 3 }) -- tables as arrays cannot have nil gaps
bindableFunction:Invoke({
[{}] = "hello", -- table keys can only be numbers OR strings
})
bindableFunction:Invoke({ -- tables keys cannot be BOTH numbers AND strings
[1] = "apple",
hello = "world",
})

Events

Callbacks

OnInvoke

Parameters

arguments: Tuple

Returns

Code Samples

Temporary DataStore

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
-- TempDataStore (Script 1)
local GetData = Instance.new("BindableFunction")
GetData.Name = "GetData"
GetData.Parent = ServerStorage
local SetData = Instance.new("BindableFunction")
SetData.Name = "SetData"
SetData.Parent = ServerStorage
local PlayerData = {}
local function getData(player)
return PlayerData[player.UserId]
end
local function setData(player, value)
PlayerData[player.UserId] = value
return PlayerData[player.UserId]
end
local function addPlayerData(player)
table.insert(PlayerData, player.UserId, 0)
end
local function removePlayerData(player)
table.remove(PlayerData, player.UserId)
end
GetData.OnInvoke = getData
SetData.OnInvoke = setData
Players.PlayerAdded:Connect(addPlayerData)
Players.PlayerRemoving:Connect(removePlayerData)
-- ActivateButton (Script 2)
local ClickDetector = Instance.new("ClickDetector")
ClickDetector.Parent = script.Parent
local function getDataClickDetector(player)
print(player.Name .. "'s Current Balance: " .. GetData:Invoke(player))
end
local function setDataClickDetector(player, value)
value = value or 100
print("Set " .. player.Name .. "'s Balance to: " .. SetData:Invoke(value))
end
local function incrementDataClickDetector(player)
local balance = GetData:Invoke(player)
print("Set " .. player.Name .. "'s Balance to: " .. SetData:Invoke(player, balance + 1))
end
ClickDetector.MouseClick:Connect(incrementDataClickDetector)
ClickDetector.RightMouseClick:Connect(setDataClickDetector)
ClickDetector.MouseHoverEnter:Connect(getDataClickDetector)
BindableFunction Addition

local bindableFunction = script.Parent
-- Define a function for use with the BindableFunction
local function AddTwoNumbers(a, b)
return a + b
end
-- Set the OnInvoke callback to be our function
bindableFunction.OnInvoke = AddTwoNumbers
-- Invoke the BindableFunction
print(bindableFunction:Invoke(25, 44))
BindableFunction Valid Values

local bindableFunction = script.Parent
-- Dummy function
bindableFunction.OnInvoke = function(...)
return ...
end
-- These values CAN be sent to/from BindableFunctions
bindableFunction:Invoke() -- nil
bindableFunction:Invoke(25) -- numbers
bindableFunction:Invoke("hello") -- strings
bindableFunction:Invoke(true) -- booleans
bindableFunction:Invoke("buy", 25) -- multiple values are OK
bindableFunction:Invoke({ 1, 2, 3 }) -- tables as arrays with no gaps
-- note the curly braces
bindableFunction:Invoke({ -- tables with string keys only
hello = "world",
goodbye = "world",
})
bindableFunction:Invoke({ -- tables with string keys
point = { 1, 2 }, -- whose values are also valid
point2 = { 3, 4 },
})
bindableFunction:Invoke({ -- tables as arrays
{ 1, 2, 3 }, -- whose values also are valid
{ hello = "world" },
})
-- These are some values you CANNOT send to/from BindableFunctions
bindableFunction:Invoke({ 1, nil, 3 }) -- tables as arrays cannot have nil gaps
bindableFunction:Invoke({
[{}] = "hello", -- table keys can only be numbers OR strings
})
bindableFunction:Invoke({ -- tables keys cannot be BOTH numbers AND strings
[1] = "apple",
hello = "world",
})