Why don't arrays/tables and variables like to cooperate?!

Since I can’t explain the situation in 1 sentence, let me clarify:

When you create a variable with a table value, then create a second variable which is equal to the first variable and then modify the second variable, you will just change the first variable but with some extra steps.
How it looks like script wise:

local currentNames = {"Muhammad", "Jacob"}
local newNames = currentNames
newNames[3] = "Joseph"
print(currentNames, newNames)
-- What I expect it to print out: {"Muhammad", "Jacob"}, {"Muhammad", "Jacob", "Joseph"}
-- What it actually prints out: {"Muhammad", "Jacob", "Joseph"}, {"Muhammad", "Jacob", "Joseph"}

You’d expect that it would NOT print the same values, but no, it prints the same values. It’s like the second variable just references the path of the first variable, not actually cloning the value of the first variable.

So I tried to do this with numbers and strings and etc. to see what would happen:

local importantNumber = 25
local newNumber = importantNumbers
newNumber = 10
print(importantNumber, newNumber)
-- What I expect it to print out: 25, 10
-- What it actually prints out: 25, 10

And it doesn’t do the same shenanigans like the tables do.

So how do I work around this in the easiest way?

When trying to fix this problem I’ve found out that you can just create a loop and add the values from the table that you don’t want to modify (currentNames) to the new variable that you want to modify (newNames):

local currentNames = {"Muhammad", "Jacob"}
local newNames = {}
for i,v in currentNames do
	newNames[i] = v
end
newNames[3] = "Joseph"
print(currentNames, newNames)
--prints out: {"Muhammad", "Jacob"}, {"Muhammad", "Jacob", "Joseph"}

But is there any easier way to do this?
I tried to search on the internet for this inconvenience but I can’t word my sentence in a way so that Google can understand.
I also do wanna blame this on lua lol

1 Like

Unlike normal variables, table variables are pointers. Therefore, they don’t duplicate like that.

3 Likes

hkep is correct. Click the three dots in the top right of your output panel in roblox, then enable “show memory address for expanded tables”

With this enabled, when you print out tables it’ll show the memory address each table variable is pointing to. In your first example, you’ll notice the memory addresses for currentNames and newNames match exactly. In your last example, you’ll notice the addresses are different because you’re creating a new table instead of pointing to an already existing table.

4 Likes

Just chipping in to say that apart from Lua, some other high languages like Python, JS, Perl, Ruby, and some others also refer to tables like that. Deep copying requires a new table (table.clone() returns a shallow copy ). Functions, threads, and most userdata are also passed by reference.

1 Like

Well that’s very interesting and very good to know. It just seems weird to me that something very important is just completely different than what you think it is. Thanks for the answers!

Now that you mention it, I have. And just to answer, it works exactly the same!
Thanks for showing me a simpler method!

2 Likes

Interesting.
Also what kind of difference is there between “shallow” and “deep” copies?

A shallow copy creates a new table that still references the same elements, while a deep copy creates a new table and new elements.

For example, if a a table had a table in it and you did a shallow copy, the table within the table would act like

this, but with a deep copy of the original table, the table inside the original table would act like how you wanted it to, e.g.

-- What it actually prints out: {"Muhammad", "Jacob"}, {"Muhammad", "Jacob", "Joseph"}
1 Like

A shallow copy will not copy a table inside of the table.

local ta = {
  {
    "ABC"
  }
}
local tb = table.clone(ta)
tb[1][1] = "DEF"
print(tb)

A deep copy will copy every table inside of the table.

1 Like

You can also make a deep clone function relatively easily:

local function DeepClone(Table)
	local Clone = {}
	
	for Key, Value in Table do
		if type(Value) == "table" then
			Clone[Key] = DeepClone(Value)
		else
			Clone[Key] = Value
		end
	end
	
	return Clone
end

local Origin = {{1}}
local Shallow = table.clone(Origin)
local Deep = DeepClone(Origin)

print(Origin[1] == Shallow[1]) -- true
print(Origin[1] == Deep[1]) -- false

Note this will not clone userdata, i.e. Roblox instances, and will strip any attached metatables.

2 Likes

@BendsSpace @hkep Thanks for the explenation! It’s a bit annoying that it doesn’t copy the table inside of the table tho.
But thank you @index_self for properly showing how to actually deep clone the table. Didn’t think my example that I figured out (even tho it works in my case) would basically function the same as table.clone().

I’ll just say, thank you guys for showing me something new!

1 Like