Maybe not just woke up let me retread that
Nope. That second piece of code won’t work.
t1 - Contains a reference to a table.
randomTable is a temporary local variable in the the function modt(). As you’ve written the code, this variable contains a reference to the SAME table referred to by t1. You’re thinking of this as if it were a reference to the variable t1, which it is not.
To reduce this problem to its fundamental parts, try this code:
local t1 = { "Bob" } -- \<\< t1 refers to Table 'A' local t2 = { "Buddy" } -- \<\< t2 refers to Table 'B' local t3 = t1 -- \<\< t3 refers to Table 'A' print(t1,t2,t3) -- Prints reference IDs of Table A, Table B, Table A print( t1[1], t2[1], t3[1] ) -- Prints "Bob", "Buddy", "Bob" t1 = t2 -- t1 now refers to Table 'B', not variable t2 print(t1,t2,t3) -- Prints reference IDs of Table B, Table B, Table A -- i.e. Table A still exists (is referred to in t3) print( t1[1], t2[1], t3[1] ) -- Prints "Buddy", "Buddy", "Bob" t1 = t3 -- t1 now refers to Table 'A', not variable t3 print(t1,t2,t3) -- Prints reference IDs of Table A, Table B, Table A -- i.e. same as original table references print( t1[1], t2[1], t3[1] ) -- Prints "Bob", "Buddy", "Bob"
Sorry for the edits, but I was clarifying and cleaning the sample.
Many thanks for the write-up, I spent a good half hour absorbing it and playing with it, and it was very insightful for me.
I still don’t fully understand the original issue however. I will try to explain it in another way. Please note I am only changing line 5 in each example.
[lua]
local t1 = { 0 }
print( t1[1] ) – prints 0
local function modta ( tt )
local t2 = { 1 }
t1[1] = t2[1]
end
modta( t1 )
print( t1[1] ) – prints 1
[/lua]
Setting the first key that t1 references to the same as t2’s first key works. After the function is complete, t1 prints the key originally assigned to t2 inside the function.
[lua]
local t1 = { 0 }
print( t1[1] ) – prints 0
local function modtb ( tt )
local t2 = { 1 }
t1 = t2
end
modtb( t1 )
print( t1[1] )-- prints 1
[/lua]
Setting t1 to reference the table t2 references also works. After the function t1 prints the key originally assigned to t2.
[lua]
local t1 = { 0 }
print( t1[1] )-- prints 0
local function modtc ( tt )
local t2 = { 1 }
tt[1] = t2[1]
end
modtc( t1 )
print( t1[1] )-- prints 1
[/lua]
Here we get into what I would like to do. Instead of using t1 directly I would like to use the parameter label of the function (tt) so that the function works on any table passed in. And it works when I reference a specific key as done above!
[lua]
local t1 = { 0 }
print( t1[1] )-- prints 0
local function modtd ( tt )
local t2 = { 1 }
tt = t2
end
modtd( t1 )
print( t1[1] )-- prints 0!
[/lua]
But then I try to accomplish the ultimate goal of using the parameter label (tt) to have a table passed in (t1 in this case) reference what t2 references in its entirety (just like in the second example, but using the parameter label this time), rather than changing each key as in the third example. This doesn’t work! Based on the previous examples, I would expect this to work.
Why can you use the parameter label (tt) to change references for individual keys but not the entire table? And what’s the best way to get the job done? Do you really have to use a for loop and alter every key reference individually?
I’ll discuss what is happening in each of your snippets.
1. Snippet 1 - t1 ( the local ) is visible to your function because your function is written after you declared t1. Thus, the function can access the variable and the table it references. Try example A below and notice that the order change causes it NOT to work.
2. Snippet 2 - Same situation. This only works because of scope and order. See Example B below where I change the order and your code stops working.
3. Snippet 3 - In this case, tt contains a reference to the table as I explained before so it works fine regardless of scope or order. See Example C below to prove that scope and order don’t matter.
4. Snippet 4 - This is basically what I talked about above. The variable tt in your final snippet contains a reference to the table that t1 points to, not a reference to the variable t1. The ID/handle of the table stored in variable t1 is passed to the function and stored in the temporary variable tt. When you replace the contents of the variable tt, you are not changing the contents of t1. Neither are you replacing the contents of the table t1 refers to. There is NO way to get references to variables. Lua doesn’t work that way. Note, because you so very much want to do this, you may not realize that if Lua did work this way, the language would be quite terrible and error prone. People would accidentally replace tables all the time.
Answer to your question:
If you want to replace the contents of a table whose reference is passed to a function, you must iterate over that reference and replace each individual indexed entry. Alternately, you can replace the table by returning a new table from your function. See example D below Again, there is absolutely no way to replace a table (outside the scope and visibility of the function) directly.
Example A
local function modta ( tt ) local t2 = { 1 } t1[1] = t2[1] end local t1 = { 0 } print( t1[1] ) -- prints 0 modta( t1 ) print( t1[1] ) -- prints 0 (unlike your prior example snippet 1)
Example B
local function modtb ( tt ) local t2 = { 1 } t1 = t2 end local t1 = { 0 } print( t1[1] ) -- prints 0 modtb( t1 ) print( t1[1] )-- prints 0 (again not like snippet 2 above)
Example C
local function modtc ( tt ) local t2 = { 1 } tt[1] = t2[1] end local t1 = { 0 } print( t1[1] )-- prints 0 modtc( t1 ) print( t1[1] )-- prints 1 (Still works because you're passing a reference to the table)
Example D
-- This function returns a table which can then be assigned to a variable if you wish -- Note: This example is only showing mechanics, and is not otherwise useful local function modtc ( tt ) local t2 = { 1 } return t2 end local t1 = { 0 } print( t1[1] )-- prints 0 t1 = modtc( t1 ) print( t1[1] )-- prints 1
Thank you very much for taking the time to explain everything.
My main confusion surrounded why snippet 3 worked but snippet 4 did not. My understanding of it after reading your explanation is that tt[1] = t2[1] is altering elements in the table itself, whereas tt = t2 is only altering the variable tt which references said table (thus t1, which only reads the table, does not pick up the change). Does that sound right?
Given that this is the case and what you’ve presented regarding order and scope, I can think of a few ways to proceed.
-
Go the example D route (this was actually the first workaround I used, as I mentioned earlier, but I discarded it because it didn’t seem elegant and I thought there would be a better way).
-
Iterate inside the function to set each key.
-
Now that you mentioned scope I just thought of this: declare a placeholder variable before the function to be used specifically for this function.
I don’t want to take much more of your time, but if off the top of your head you think any of these ideas are particularly good or bad I would love to hear why briefly!
Yes, that is exactly right. The core of the issue is that you can can’t pass variables by reference, only Objects and Tables.
All those options will work, but I often use option 3 if I know I won’t be modifying the code or moving it around later. It isn’t exactly elegant (heck it’s simply a cheat taking advantage of scope and visibility rules), but making a game/app isn’t about elegance. It is about getting the code written and working (well). This option has the benefit of speed, whereas 2 is slow(er).
Cheers,
Ed
I understand. Well once again, thank you so much for taking the time! I’ve learned a great deal from your posts (more than I had originally planned for, and that’s a good thing).