Mixed tables in Remote/Bindable Event/Function

As a Roblox developer, it is currently impossible to send mixed tables in remote/bindable events/functions.

This is a very annoying limitation that often requires rewriting aspects of what I’m doing just so that it will work.

( I did search to see if this was already suggested, couldn’t find any though )

14 Likes

Also, from what I understand this shouldn’t be too hard to fix, at the moment it uses json which doesn’t support mixed tables so would just need a different serialisation function for tables?

Encode the table in JSON before firing, and then when received, decode it.

JSON doesn’t support mixed tables.

And if I did encode it in whatever beforehand, that would require each script that connects to the event decode it, which is not very performant nor very usable in terms of third party modding of any script I make ( This is for a free model that supports third-party mods )

Show me what the table looks like that you’re trying to send over?

I have multiple different tables that encounter this issue, this isn’t a problem limited to one specific table.

Why do you have mixed tables? There are few cases where I find mixed tables to actually be the right design choice. Could you break up these tables into nested tables with sequential and referential parts? What is just one example where you are having trouble sending a mixed table?

Ultimately, the issue probably lies in the fact that you are mixed data structures. A mixed index table isn’t really a true data structure. You are combining an array with a map and that really doesn’t make sense from a computer science perspective.

6 Likes

Yeah, I have to agree with @TheNickmaster21 on this. It’s pretty easy to design structures that avoid mixed tables.

I can’t think of any real-world applications where a mixed table-like structure is used.

2 Likes

It’s mostly nil values causing the issues, and the fact that you can’t do { { X = 1, X = 2 }, { X = 1, X = 2 }

You should be able to do that. A mixed table only relates to the immediate table, not sub-tables. I’ve done it many times with DataStores and such.

Interesting, not sure what was causing the error then! I’ll do some tests and post here when I’m done.

This is incorrect, all sub-tables (and sub-sub-tables, and sub-sub-sub, etc…) need to be non-mixed right now. The property applies to the entire structure of tables, not just top-level. (This is most likely because it is marshalled into JSON internally)

> workspace.Event:Fire(
   {
      "hello",
      {
         [2] = "world",
         [5] = "!!!"
      }
   }
)
18:02:44.507 - Cannot convert mixed or non-array tables: keys must be strings
1 Like

This is the table I’m having issues with:

{ [ 2 ] = { 1, 2 } }

Don’t have the issue with this though

{ nil, { 1, 2 } }

As a temporary workaround, if your keys can only be numbers, you can just tostring the indices that you set and then turn them back into numbers at the receiving end.

That’s because in the first example, you have an array of numerical indices but it doesn’t start at 1 (and also it may have no holes, if there were multiple indices). In the second example, you don’t supply any indices, so it just becomes an array which is allowed.

1 Like

Yet { 1, 2, 3, B = 1 } works?

I think I may be misunderstanding what a mixed table is?

If you actually print the result of that table being passed through a Bindable/RemoteEvent, you’d find that the B = 1 probably got cut off. That’s Roblox’s mistake for not throwing an error there.

2 Likes

Figured out I can use the following function to make it work for now:

local function Fill( Table, a, max )
	a = a or 1
	if not max then
		max = 1
		for a, b in pairs( Table ) do
			max = math.max( max, a )
		end
	end
	if a > max then return end
	return Table[ a ], Fill( Table, a + 1, max )
end

and then

Event:Fire( { Fill{ [ 2 ] = { 1, 2 } } )

-- Original
{ [ 2 ] = { 1, 2 } }

-- New
{ [ 2 ] = { 1, 2 } }

Ok, weird, that must be an issue with Remote/BindableEvents, because it definitely works in DataStores.

This code demonstrates the culling that will occur.

local bindable = Instance.new("BindableEvent")

local function printTable(tab, depth)
	depth = depth or 0
	local indent = string.rep("\t", depth)
	for i, v in pairs(tab) do
		if type(v) == "table" then
			print(indent .. i .. " : {")
			printTable(v, depth + 1)
			print(indent .. "}")
		else
			print(indent .. i .. ": " .. tostring(v))
		end	
	end
	
end

bindable.Event:Connect(printTable)
bindable:Fire({ 1, 2, 3, B = 1 })

Output:

1: 1
2: 2
3: 3
1 Like

Made a bug report for this