Scoping rules in Lua - lua

I was testing the scope for Lua and noticed something unexpected. The following code does not print the localMainVariable.
function functionScope()
print( "\nIn function")
print( "globalMainVariable: " .. globalMainVariable )
if (localMainVariable ~= nil) then print( "localMainVariable: " .. localMainVariable ) end
end
globalMainVariable = "Visible"
local localMainVariable = "Visible"
functionScope()
But the following code does print localMainVariable.
globalMainVariable = "Visible"
local localMainVariable = "Visible"
function functionScope()
print( "\nIn function")
print( "globalMainVariable: " .. globalMainVariable )
if (localMainVariable ~= nil) then print( "localMainVariable: " .. localMainVariable ) end
end
functionScope()
I know it has something to do with where the localMainVariable was declared, but I thought making it local would limit the scope of the variable. What is the actual rule?
Thanks

The scope of a local variable begins at the first statement after its
declaration and lasts until the last non-void statement of the
innermost block that includes the declaration.
Lua manual

Related

Understanding LUA Callbacks

For example this code:
-- Defining a function that takes a callback function as a parameter
function HelloMessage(callback)
-- Below you are passing the string "sup" as a parameter to the callback function
callback("sup")
end
-- Here, below, we are calling the function defined earlier
-- and we pass a callback function to it (a.k.a. "handler")
HelloMessage(function(message)
print(message) -- "sup" gets printed
end)
I did not understand how it works. How does it pass the sup into the message parameter??
HelloMessage(function(message) print(message) end)
is basically equivalent to
do
local callback = function(message) print(message) end
callback("sup")
end
which is equivalent to
do
local message = "sup"
print(message)
end
function(message) print(message) end defines an anonymous function that is immediately referenced by the function argument callback which is a local variable in HelloMessage's scope.
cb_function = function( var_txt ) print("var_txt = ", var_txt ) end
function HelloMessage( callback_func )
if type( callback_func ) == "function" then --just chek is func passed
callback_func( "Print to callback function" )
end
end
HelloMessage( cb_function ) --passing call back function

Garrys Mod Lua problem (check equal and print)

I don't have any errors.
My scrips can take the name of new weapon but it cant check equal of hololink_swep.
The print of equal doesn't appear.
Please help.
My code:
hook.Add( "PlayerSwitchWeapon", function( ply, oldWeapon, newWeapon )
print( "Your new weapon is " .. newWeapon:GetClass() .. "." );
if ( newWeapon == hololink_swep ) then
print( "This weapon is speciall" .. newWeapon:GetClass() .. "." );
end
end );
if (tostring(newWeapon) == tostring(hololink_swep) )
hook.Add("PlayerSwitchWeapon", "some name of hook", function(ply, oldWeapon, newWeapon)
print("Your new weapon is " .. newWeapon:GetClass() .. ".")
if (newWeapon == "hololink_swep") then
print("This weapon is speciall" .. newWeapon:GetClass() .. ".")
end
end)
also do not forget to name your hook. I named it for example some name of hook.

How do we change the way print displays a table

Assuming I have a piece of code such as the following
aTable = {aValue=1}
aTable_mt = {}
print(aTable)
What must I do to make Lua print something like aTable current aValue = 1 as opposed to table: 0x01ab1d2.
So far I've tried setting the __tostring metamethod but that doesn't seem to be invoked by print. Is there some metamethod I've been missing or does the answer have nothing to do with metamethods?
__tostring works:
aTable = {aValue=1}
local mt = {__tostring = function(t)
local result = ''
for k, v in pairs(t) do
result = result .. tostring(k) .. ' ' .. tostring(v) .. ''
end
return result
end}
setmetatable(aTable, mt)
print(aTable)
This prints aValue 1 (with one extra whitespace, remove it in real code). The aTable part is not available, because aTable is a variable that references the table, not the content of the table itself.
I'm not sure how you set the metamethod, but the following code prints "stringified" for me:
local aTable = {a = 1, b = 2}
setmetatable(aTable, {__tostring = function() return "stringified" end})
print(aTable)
If you want lua to generally print all tables human readable, you could
hook up/overwrite the print function:
local orig_print = print
print = function(...)
local args = {...}
for i,arg in ipairs(args) do
if type(arg) == 'table' then
args[i] = serialize(arg)
end
end
orig_print(table.unpack(args))
end
serialize could be serpent or some other lib from here
Note that this must be done before any other module/script is loaded.

Multi-threading functions in Computer Craft

I'm working on a project where I want to update the clock on screen say every 5 seconds unless the user inputs something. This is the code I have so far,
function thread1()
term.clear()
term.setCursorPos(1,1)
write (" SteveCell ")
local time = os.time()
local formatTime = textutils.formatTime(time, false)
write (formatTime)
print ("")
print ("")
for i=1,13 do
write ("-")
end
print("")
print ("1. Clock")
print ("2. Calender")
print ("3. Memo")
print ("4. Shutdown")
for i=1,13 do
write ("-")
end
print ("")
print ("")
write ("Choose an option: ")
local choice = io.read()
local choiceValid = false
if (choice == "1") then
-- do this
elseif (choice == "2") then
-- do that
elseif (choice == "3") then
-- do this
elseif (choice == "4") then
shell.run("shutdown")
else
print ("Choice Invalid")
os.sleep(2)
shell.run("mainMenu")
end
end
function thread2()
localmyTimer = os.startTimer(5)
while true do
local event,timerID = os.pullEvent("timer")
if timerID == myTimer then break end
end
return
end
parallel.waitForAny(thread1, thread2)
shell.run("mainMenu")
Unfortunately it's not working. If someone could help me with this, I would really appreciate it. Thanks :)
You want to do something like this (Im not doing the correct on screen drawing, only the time)
local function thread1_2()
-- both threads in one!
while true do
local ID_MAIN = os.startTimer(5)
local ID = os.startTimer(0.05)
local e = { os.pullEvent() }
if e[1] == "char" then
-- Check all the options with variable e[2] here
print( string.format( "Pressed %s", e[2] ) )
break -- Getting out of the 'thread'
elseif e[1] == "timer" and e[2] == ID then
ID = os.startTimer(0.05) -- shortest interval in cc
redrawTime() -- Redraw and update the time in this function!!!
elseif e[1] == "timer" and e[2] == MAIN_ID then
break
end
end
end
Also, ask this in the proper forum, you have more chance getting an answer there!
Another note, get more into event handling, it really helps.
FYI Lua doesn't have 'multi-threading' as in executing multiple routines simultaneously. What it does have is 'thread parking.' You can switch between routines (yielding) and switch back and it will resume where it left off, but only a single routine will be active at any given time.
This is my go-to Lua reference, which explains in detail:
http://lua-users.org/wiki/CoroutinesTutorial

How can I print a joined table of strings in Lua?

Okay I am working on a script for my Oxide Lua Plugin, and I am also just learning Lua Script so I am not real sure how to do this.
-- *******************************************
-- Broadcasts a Server Notification
-- *******************************************
function PLUGIN:cmdNotice( netuser, args )
table.concat(args," ")
local allnetusers = rust.GetAllNetUsers()
if (allnetusers) then
for i=1, #allnetusers do
local netuser = allnetusers[i]
rust.Notice(netuser, args[1]))
rust.SendChatToUser(netuser, "Message Sent:" .. args[1])
end
end
end
What I am trying to do is fix this so I do not have to manually encase my notice in "".
For example, as the code stands, while I am in game in rust if I use the /notice command I have two outcomes.
Example 1
/notice hello everone
will only produce
hello
but if I do
/notice "hello everyone"
will give the entire message. So I am a little confused.
So my new code should look like this
-- *******************************************
-- Broadcasts a Server Notification
-- *******************************************
function PLUGIN:cmdNotice( netuser, args )
table.concat(args," ")
local allnetusers = rust.GetAllNetUsers()
if (allnetusers) then
for i=1, #allnetusers do
local netuser = allnetusers[i]
rust.Notice(netuser, table.concat(args, " " ))
rust.SendChatToUser(netuser, "Message Sent:" .. table.concat(args, " "))
end
end
end
Edit 3/15/2014
Okay cool so in a since I can also do this as well correct?
function PLUGIN:cmdNotice( netuser, args )
if (not args[1]) then
rust.Notice( netuser, "Syntax: /notice Message" )
return
end
local allnetusers = rust.GetAllNetUsers()
if allnetusers then
for i=1, #allnetusers do
local netuser = allnetusers[i]
local notice_msg = table.concat(args," ")
rust.Notice(netuser, notice_msg)
rust.SendChatToUser(netuser, "Message Sent:" .. notice_msg)
end
end
end
To clarify what #EgorSkriptunoff said, table.concat returns the joined table, but it does not change the value of args. Since you don't save the joined return value, your line 1 inside the function is useless. As an alternative to his approach, you could do rust.SendChatToUser ( netuser, "Message Sent:" .. table.concat(args, " " ).
My guess is that you were thinking (?) that the joined strings would be saved in the args table as the first item in the table? That's not what happens. The table itself remains unchanged, so when you print args[1], you get only the first string of the array. It "works" when you quote the message because in that case the entire message goes in as one thing, and the array only has an arg[1].
Here's what is going on
t = { "hello", "I", "must", "be", "going"}
-- Useless use of concat since I don't save the return value or use it
table.concat(t, " ")
print(t) -- Still an unjoined table
print(t[1]) -- Prints only "hello"
print(table.concat(t, " ")) -- Now prints the return value
Edit: In response to the follow-up question, see my comments in the code below:
function PLUGIN:cmdNotice( netuser, args )
table.concat(args," ") -- This line is not needed.
local allnetusers = rust.GetAllNetUsers()
-- Lua doesn't count 0 as false, so the line below probably doesn't do
-- what you think it does. If you want to test whether a table has more
-- than 0 items in it, use this:
-- if #allnetusers > 0 then...
if allnetusers then
for i=1, #allnetusers do
local netuser = allnetusers[i]
rust.Notice(netuser, table.concat(args, " " ))
rust.SendChatToUser(netuser, "Message Sent:" .. table.concat(args, " "))
end
end
end

Resources