Lua huh wha? : I don't understand how this assignment is working

Here’s my code:

    testVariable = "prime rib"

    --a function that replaces a target with a string:
    replacer = function (target, string)
        target = string
        --below should show the target as having the string's value:
        print(target)
    end

    replacer(testVariable,"finger food")

    --below should also show the target as having the string's value, right?
    print (testVariable)

Here’s the output:

finger food
prime rib

Shouldn’t both the outputs be “finger food?” I must be missing something important here.

Functions in lua are using call-by-value, so you don’t send a pointer to your variable into the function.

If you send in an table, you can modify it’s contents in the function


x = {a="a"}

function replacer(target, string)
   target.a = string
end

replacer(x, "hello")

So, when you say “call-by-value” that means that a variable for a string gets turned into the string itself when used in a function call? Wow that might also clear up a lot of other problems I’m seeing.

Actually, I’d say it’s better to think of things the other way around. Everything in lua is a pointer. The key is that everything gets dereferenced automatically and as much as possible.

So let’s go through the code:

testVariable = "prime rib"

Lua creates a string object, which is a memory address, sticks the string “prime rib” in there. testVariable contains a pointer to this address.

replacer(testVariable,"finger food")

This calls the function replacer (or rather, the function that replacer points to!) with two pointers. One is a pointer to “prime rib”, the other is a pointer to “finger food” (which has been created on the fly).

replacer = function (target, string)

Here’s the function definition, but let us imagine it being called as above. When we call replacer(testVariable, "finger food") then lua does effectively:

do -- to cordon off the function
    local target = testVariable
    local string = "finger food"

The important bit here is target = testVariable. This makes target a copy of testVariable. Recall that testVariable was a pointer to “prime rib”, so now target is also a pointer to “prime rib”. But, and this is the crucial part, there is no link between target and testVariable. In particular, target is not a pointer to testVariable, but target is a pointer to what testVariable is a pointer to. Thus in:

local target = testVariable

the examination of testVariable leads to it being dereferenced, whence this means:

local target = <whatever testVariable is pointing to>

Let’s continue:

target = string

So now target points to whatever string pointed to (namely “finger food”), but this assignment has done nothing to testVariable since there is no link between target and testVariable.

@tnlogy’s suggestion of using tables is a good one and one that I frequently use. I have many functions of the form:

function do_something_to(t)
    t.field = 32
end

so that I can write do_something_to(my_table).

The point here being that t points to the same thing that my_table points to: a table. So manipulating that table via t affects the same thing that my_table points to.

This doesn’t work with strings because strings are immutable. So you can’t sneak in to lua’s memory and replace “prime rib” with “finger food”: it won’t let you. Any time that you think you are manipulating a string then you are actually creating a new string and updating the pointer to point to the new one.

One way to do what your code would like to do is to manipulate the _G table:

testVariable="prime rib"
replacer = function(target,source)
  _G[target] = source
  print(_G[target])
end
replacer("testVariable","finger food")
-> finger food
print(testVariable)
-> finger food

But notice that I pass the name of the variable, not the variable itself.

Wow, Andrew, thanks for that.