This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Ferios's profile picture

"attempt To Write To Global"

Started by Ferios, 21 February 2012 - 06:09 AM
Ferios #1
Posted 21 February 2012 - 07:09 AM
Got a function that looks for events and logs them in a local variable outside of the function so that another function can use it. That other function is run WITH this function with parallel.waitForAny(). I use os.pullEventsRaw() to get my events. Here are the code pieces :

EVENTS

function mngrEvents()
 Events = {}
 term.setCursorPos(1,1)
 write('Events Manager online')
 while true do
  ev, p1, p2 = os.pullEventRaw()
  table.insert(Events, {ev,p1,p2,false})
  i = 1
  while not(Events[i] == nil) do
   if Events[i][4] then
	table.remove(Events, i)
   else
	i = i + 1
   end
  end
  --ev, p1, p2 = nil,nil,nil
 end
end

USING EVENTS

function mngrKeyboard()
 term.setCursorPos(1,2)
 write('Keyboard Manager online')
 while true do
  i = 0
  while not(Events[i] == nil) do
   if Events[i][1] == "char" then
    pcall(write(Events[i][2]))
    fncMoveCursor()
    Events[i][4] = true
   end
   i = i + 1
  end
  pcall(sleep(0.01))
 end
end

PARALLEL CALL

parallel.waitForAny(
 function()
  mngrEvents()
 end,
 function()
  mngrKeyboard()
 end
)

I get the error on the second loop in the mngrEvents function. The commented line was an attempt to correct the problem. With Casper's debugger, it says Variable: ev = timer then tells me that the code attempted to write to a global variable (title's the exact wording). If I uncomment ev = nil then the line stating the present value of the variable disappears.
I'll include the full backtrace file.[attachment=30:debugtraceback.txt]
Espen #2
Posted 21 February 2012 - 11:19 AM
The only error I got was "bad argument #1: value expected"
And that was because you made calls to pcall() in the wrong way.
You have to pass to it the name of the function and all its arguments as separate arguments.
Instead of…

pcall(write(Events[i][2]))
pcall(sleep(0.01))
…you should use it like this…

pcall(write, Events[i][2])
pcall(sleep, 0.01)

After these corrections I don't get any error messages anymore. But then again I had to comment out the call to fncMoveCursor(), because you didn't provide the code to that. Could you perhaps post the code to that function as well?

But anyway, if you're told that your program has attempted to write to a global value, then you can try to either rename some of your variable names, because they might clash with a global variable name; or you can declare the variables you use as 'local', which is always good practice.
So instead of …

ev, p1, p2 = os.pullEventRaw()
… try to do…

local ev, p1, p2 = os.pullEventRaw()

But remember that variables declared as 'local' only exist within the code-block they were declared as local!
That means in your case that ev, p1 and p2 will only exist within your while-loop. But since you're using them only within this loop it's no problem for now.
If you'd want to make use of them within your whole program, then you could e.g. put this declaration at the top of your program…

local ev, p1, p2
… and then use them wherever you like in your program.

EDIT:
VERY IMPORTANT:
Didn't see this until now, but you absolutely have to make your counter-variable local in both functions, because if you're not making them local and use the same name, then the variables of the two functions are influencing themselves across functions!
So instead of…
i = 1
… do this instead in both functions…
local i = 1
Edited on 21 February 2012 - 10:33 AM
Advert #3
Posted 21 February 2012 - 11:32 AM
Got a function that looks for events and logs them in a local variable outside of the function so that another function can use it. That other function is run WITH this function with parallel.waitForAny(). I use os.pullEventsRaw() to get my events. Here are the code pieces :

EVENTS

function mngrEvents()
 Events = {}
 term.setCursorPos(1,1)
 write('Events Manager online')
 while true do
  ev, p1, p2 = os.pullEventRaw()
  table.insert(Events, {ev,p1,p2,false})
  i = 1
  while not(Events[i] == nil) do
   if Events[i][4] then
	table.remove(Events, i)
   else
	i = i + 1
   end
  end
  --ev, p1, p2 = nil,nil,nil
 end
end

USING EVENTS

function mngrKeyboard()
 term.setCursorPos(1,2)
 write('Keyboard Manager online')
 while true do
  i = 0
  while not(Events[i] == nil) do
   if Events[i][1] == "char" then
    pcall(write(Events[i][2]))
    fncMoveCursor()
    Events[i][4] = true
   end
   i = i + 1
  end
  pcall(sleep(0.01))
 end
end

PARALLEL CALL

parallel.waitForAny(
 function()
  mngrEvents()
 end,
 function()
  mngrKeyboard()
 end
)

I get the error on the second loop in the mngrEvents function. The commented line was an attempt to correct the problem. With Casper's debugger, it says Variable: ev = timer then tells me that the code attempted to write to a global variable (title's the exact wording). If I uncomment ev = nil then the line stating the present value of the variable disappears.
I'll include the full backtrace file.[attachment=30:debugtraceback.txt]
Hi Ferios, the "Attempt to write to global" error is coming from this snippet of code inside bios.lua:


local bProtected = true
local function protect( _t )
	setmetatable( _t, { __newindex = function( t, k, v )
		if bProtected then
			error( "Attempt to write to global" )
		else
			rawset( t, k, v )
		end
	end } )
end

What this means, is that you are trying to write to something that's protected, that's most likely an API.

I can't see from your code where this is hapening, but your code is a shining example of why you shouldn't use globals, too!

Both your loops use the global variable i, and you use parallel: Your code will run as a tag-team, and your first loop will reset i every time it gets an event. Use local infront of your varaibles to make them local; I would reccomend doing it like this:

local Events = {}

function mngrEvents() 
 local i
 ...
end

function mngrKeyboard()
 local i
 ...
end


In addition to that, you aren't using pcall right!
Take a look at this:

Pcall is called as follows:

local sucess, result = pcall(function, param1 [, param2…]) – you never call the function you're pcalling! pcall does that for you.


So, for example; where you are trying to call sleep with pcall:

pcall(sleep(0.01)) – This won't do what you want!
pcall(sleep, 0.01) – This is the correct syntax.


Also: for your parallel call, you can use your functions directly:


parallel.waitForAny(
  mngrEvents
 end,
 function()
  mngrKeyboard()
 end
)
Espen #4
Posted 21 February 2012 - 11:33 AM
Waah, ninja'd my edit Advert! :P/>/>
But your explanation is much more detailed and comprehensive, me gusta. :)/>/>

EDIT:
Lol, saw your following post, after I inserted the second line of this post.
Pardox-Posting ftw! :D/>/>
Edited on 21 February 2012 - 10:37 AM
Advert #5
Posted 21 February 2012 - 11:35 AM
Waah, ninja'd my edit Advert! :)/>/>
You ninja'd this :P/>/> I started my post before you posted!
Ferios #6
Posted 21 February 2012 - 07:00 PM
Also: for your parallel call, you can use your functions directly:


parallel.waitForAny(
  mngrEvents
end,
function()
  mngrKeyboard()
end
)
I tried using the function directly, but the terminal didn't go any other function than the first and he froze then shutdown. Really weird, but like that it works. Also, I have about 8 functions to put in the parallel, and it works the way I did it.
I'm new to lua, so I didn't knew that not putting Local creates a global variable… I'll remember that!
Thanks for your help, I'm going to test this and I'll tell you the results (and the possible bugs XD).
Advert #7
Posted 21 February 2012 - 07:01 PM
Also: for your parallel call, you can use your functions directly:


parallel.waitForAny(
  mngrEvents
end,
function()
  mngrKeyboard()
end
)
I tried using the function directly, but the terminal didn't go any other function than the first and he froze then shutdown. Really weird, but like that it works. Also, I have about 8 functions to put in the parallel, and it works the way I did it.
I'm new to lua, so I didn't knew that not putting Local creates a global variable… I'll remember that!
Thanks for your help, I'm going to test this and I'll tell you the results (and the possible bugs XD).
Seems like the editor derped on me; remove the function() and two ends from that line, and it should work.