Although arguments to Lua functions are passed by value, meaning they're duplicates, and although local variables in functions are passed by value as returns, arguments and returns of tables are a special case, because tables are ALWAYS passed and assigned by REFERENCE! This means that what the function does to a table argument is visible in the calling routine after the called function returns. Likewise, if you change a table obtained from a function return, that change may be visible in other places. Tables are passed and assigned by reference. The only two ways to copy a table are:
|
#!/usr/bin/luaThe preceding code, as expected, creates the following output:
function hello()
print("Hello World")
end
hello()
slitt@mydesk:~$ ./hello.luaNow let's throw in an argument:
Hello World
slitt@mydesk:~$
#!/usr/bin/luaNotice that Lua itself doesn't check the type of the argument. We passed it a string the first time and a number the second, and it took them both. Of course usually you have problems inside the function if you use a numeric to call what should have been a string or vice versa, but in this case string.format() converted the number to a string. Here's the resulting output:
sf = string.format
function hello(name)
print(sf("Hello %s!", name))
end
hello("Alfred Anderson")
hello(321)
slitt@mydesk:~$ ./hello.luaIf you really want to typecheck the incoming argument, do it inside the function:
Hello Alfred Anderson!
Hello 321!
slitt@mydesk:~$
#!/usr/bin/luaHere's the output:
sf = string.format
function hello(name)
assert(type(name) == "string",
"ERROR: Only strings may be passed into hello()")
print(sf("Hello %s!", name))
end
hello("Alfred Anderson")
hello(321)
slitt@mydesk:~$ ./hello.luaIn the preceding, putting quotes around the 321 make it a string and prevent the error message.
Hello Alfred Anderson!
/usr/bin/lua: ./hello.lua:5: ERROR: Only strings may be passed into hello()
stack traceback:
[C]: in function 'assert'
./hello.lua:5: in function 'hello'
./hello.lua:11: in main chunk
[C]: ?
slitt@mydesk:~$
#!/usr/bin/luaThe preceding passes back the name preceded by "Howdy ", and the two calls to hello() are now in print statements so they print the return value. Here's the resulting output:
sf = string.format
function hello(name)
assert(type(name) == "string",
"ERROR: Only strings may be passed into hello()")
print(sf("Hello %s!", name))
return("Howdy " .. name)
end
print(hello("Alfred Anderson"))
print(hello("321"))
slitt@mydesk:~$ ./hello.lua
Hello Alfred Anderson!
Howdy Alfred Anderson
Hello 321!
Howdy 321
slitt@mydesk:~$
function hello()The preceding syntax is just a Lua syntax shortcut (commonly known as "syntactic sugar") for the more general syntax of assigning an unnamed function to a variable:
print("Hello World")
end
hello = function()Or the one with arguments:
print("Hello World")
end
hello = function(name)Functions are just data that can get assigned. See this:
print(sf("Hello %s!", name))
end
#!/usr/bin/luaAll you've done is assigned the exact same function to a second name, so the preceding code should simply print out "Hello World" twice. And indeed, when we run it, we get the following:
function hello ()
print("Hello World")
end
hi = hello
hello()
hi()
slitt@mydesk:~$ ./hello.luaPerhaps you've noticed that in a lot of the programs in Litt's Lua Laboratory I start with the following:
Hello World
Hello World
slitt@mydesk:~$
sf=string.formatThat's to save line length and keystrokes. Instead of having to type out string.format over and over again, letting lines become longer and longer, I just type out sf. See the following:
#!/usr/bin/luaProducing:
sf=string.format
print(sf("%s %s picked %d pickled peppers","Peter", "Piper", 5))
slitt@mydesk:~$ ./hello.luaBut functions-as-data is a lot more powerful than name slight of hand. Callback functions become trivial in Lua. Things like event driven programming become much easier. Combine this with OOP and you have some serious power.
Peter Piper picked 5 pickled peppers
slitt@mydesk:~$
#!/usr/bin/luaSo notice that on the call to kvsplit(), the left side has a comma delimited list of variables to be filled. Here's the output:
sf = string.format
function kvsplit(strng)
local key = string.match(strng, "^.-=")
key = string.sub(key, 1, -2)
key = string.match(key, "%S.*%S")
value = string.match(strng, "=.*%S")
value = string.sub(value, 2)
value = string.match(value, "%S.*")
return key, value
end
local key, value = kvsplit(" name = Steve Litt ")
print(sf("Key=>%s<, value=>%s<.", key, value ))
local key, value = kvsplit("job=troubleshooter")
print(sf("Key=>%s<, value=>%s<.", key, value ))
slitt@mydesk:~$ ./hello.luaIt's just as expected.
Key=>name<, value=>Steve Litt<.
Key=>job<, value=>troubleshooter<.
slitt@mydesk:~$
#!/usr/bin/luaHere the special table arg contains everything passed in through ... and can iterate through it.
sf=string.format
function printargs(...)
for i=1, #arg do
print(sf("i=>%s<, v=>%s<", tostring(i), tostring(arg[i])))
end
print()
end
printargs("one")
printargs("one","two")
printargs("one","two", "three")
slitt@mydesk:~$ ./test.luaYou can also have named arguments before the varargs:
i=>1<, v=>one<
i=>1<, v=>one<
i=>2<, v=>two<
i=>1<, v=>one<
i=>2<, v=>two<
i=>3<, v=>three<
slitt@mydesk:~$
#!/usr/bin/luaThe preceding code should print the first argument alone on its line, and then any and all other arguments in strings. That's indeed what happens:
sf=string.format
function printargs(namedarg, ...)
print(namedarg)
for i=1, #arg do
print(sf("i=>%s<, v=>%s<", tostring(i), tostring(arg[i])))
end
print()
end
printargs("one")
printargs("one","two")
printargs("one","two", "three")
slitt@mydesk:~$ ./test.luaYou can also pass varargs on to other functions. Consider this:
one
one
i=>1<, v=>two<
one
i=>1<, v=>two<
i=>2<, v=>three<
slitt@mydesk:~$
#!/usr/bin/luaSo passargs() is printing the first (name) argument and then passing the varargs to printargs(), which loops through printing them. The resulting output follows:
sf=string.format
function printargs(...)
for i=1, #arg do
print(sf("In printargs, i=>%s<, arg=>%s<",i, arg[i]))
end
end
function passargs(namedarg, ...)
print(sf("In passargs, namedarg=>%s<",namedarg))
printargs(...)
print()
end
passargs("one")
passargs("one","two")
passargs("one","two", "three")
slitt@mydesk:~$ ./test.lua
In passargs, namedarg=>one<
In passargs, namedarg=>one<
In printargs, i=>1<, arg=>two<
In passargs, namedarg=>one<
In printargs, i=>1<, arg=>two<
In printargs, i=>2<, arg=>three<
slitt@mydesk:~$
#!/usr/bin/luaSo function showstringreverse() called function reverse(), which was nested in showstringreverse(). The output is just what you'd expect.
sf=string.format
function showstringreverse(str)
function reverse(s)
return string.reverse(s)
end
print(reverse(str))
end
showstringreverse("abcde")
slitt@mydesk:~$ ./test.luaIn this case there was little advantage to nesting the function as opposed to putting it above. But occasionally you might have a function so specific to another that nesting makes sense. And of course nesting functions is how you get closures, which is covered on another page of Litt's Lua Laboratory. Closures are extremely powerful.
edcba
slitt@mydesk:~$
#!/usr/bin/luaThe output is:
sf=string.format
point = {x=4, y=6}
point.show = function(self)
print(sf("x=%d, y=%d",self.x,self.y))
end
point:show()
slitt@mydesk:~$ ./test.luaBecause we haven't covered tables yet this might not make a lot of sense to you yet, but it's an example of storing an anonymous function as point.show.
x=4, y=6
slitt@mydesk:~$
myvar = 5These are local
local myvar = 5My opinion is every non-function variable should be local unless you have an incredibly good reason to make it global. Global variables inevitably cause problems.
local myother
myother = 5
[ Troubleshooters.com| Code Corner | Email Steve Litt ]
Copyright
(C) 2011 by Steve Litt --Legal