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

Attempt to index ? (a nil value) but can't find mistake

Started by rpg4mc, 12 July 2013 - 06:10 AM
rpg4mc #1
Posted 12 July 2013 - 08:10 AM
Title: Attempt to index ? (a nil value) but can't find mistake

I'm trying to teach myself the advanced monitor stuff and I started out by trying to fill the complete screen. On Ln 17 I got a 'nil value' error but I have no idea why. Please help :)/>
function StartMonitor()
  local wm, hm, monitor
  local monitor = peripheral.wrap("top")
  local w,h = term.getSize()
  monitor.setTextScale(1)
  monitor.setCursorPos(1,1)
  monitor.clear()
  monitor.write("Hello World")
  wm, hm = monitor.getSize()
  print("Monitor size = " ..wm..","..hm)
  print("Terminal size = " ..w..","..h)
 
end
StartMonitor()
for y=1,hm+1 do
  monitor.write(string.rep("*",wm))
  monitor.setCursorPos(1,y)
end
monitor.setCursorPos(1,y)
LucasShadow #2
Posted 12 July 2013 - 12:13 PM
Its a context/scope issue. monitor, wm, and hm are all contained within the StartMonitor function. When you call monitor.write, the program doesn't know what monitor is. A revised version of the program is here:


--Global Vars
ghm = 0
gwm = 0

--Function
function StartMonitor()
	local wm, hm, monitor
	local monitor = peripheral.wrap("top")
	local w,h = term.getSize()
	monitor.setTextScale(1)
	monitor.setCursorPos(1,1)
	monitor.clear()
	monitor.write("Hello World")
	wm, hm = monitor.getSize()
	ghm = hm
	gwm = wm
	print("Monitor size = " ..wm..","..hm)
	print("Terminal size = " ..w..","..h)
	
	--Return our monitor
	return monitor
end

--Get our monitor
myMonitor = StartMonitor()

--Write our stuff
for y=1,ghm+1 do
	myMonitor.write(string.rep("*",gwm))
	myMonitor.setCursorPos(1,y)
end
rpg4mc #3
Posted 12 July 2013 - 12:34 PM
Oh I see, thanks!
theoriginalbit #4
Posted 12 July 2013 - 05:51 PM
Alternatively you can do this


local monitor = peripheral.wrap("top")
local wm, hm = monitor.getSize()

function StartMonitor()
  local w,h = term.getSize()
  monitor.setTextScale(1)
  monitor.setCursorPos(1,1)
  monitor.clear()
  monitor.write("Hello World")
  print("Monitor size = " ..wm..","..hm)
  print("Terminal size = " ..w..","..h)
end

StartMonitor()

for y=1,hm+1 do
  monitor.write(string.rep("*",wm))
  monitor.setCursorPos(1,y)
end

monitor.setCursorPos(1,y)

Also as a slight side note, there are two functions within the term API, term.redirect and term.restore, which allow you to get the terminal to act on a different object and return back to the normal terminal respectively. term.redirect makes it very nice when dealing with monitors as you can then use the write and print functions on the monitor to allow for newline characters `\n` and it gives you line wrapping too.

local mon = peripheral.wrap("right")

term.redirect(mon)

print("I'm printing on the monitor")
write("So am I, and if this line is long enough on the monitor it will wrap down to the next line too, unlike using mon.write! Also I can use newlines now\nand it doesn't print a ?")

term.restore()

print("I'm back on the computer")
rpg4mc #5
Posted 14 July 2013 - 07:12 AM
Alternatively you can do this


local monitor = peripheral.wrap("top")
local wm, hm = monitor.getSize()

function StartMonitor()
  local w,h = term.getSize()
  monitor.setTextScale(1)
  monitor.setCursorPos(1,1)
  monitor.clear()
  monitor.write("Hello World")
  print("Monitor size = " ..wm..","..hm)
  print("Terminal size = " ..w..","..h)
end

StartMonitor()

for y=1,hm+1 do
  monitor.write(string.rep("*",wm))
  monitor.setCursorPos(1,y)
end

monitor.setCursorPos(1,y)

Also as a slight side note, there are two functions within the term API, term.redirect and term.restore, which allow you to get the terminal to act on a different object and return back to the normal terminal respectively. term.redirect makes it very nice when dealing with monitors as you can then use the write and print functions on the monitor to allow for newline characters `\n` and it gives you line wrapping too.

local mon = peripheral.wrap("right")

term.redirect(mon)

print("I'm printing on the monitor")
write("So am I, and if this line is long enough on the monitor it will wrap down to the next line too, unlike using mon.write! Also I can use newlines now\nand it doesn't print a ?")

term.restore()

print("I'm back on the computer")

Oh I get it now, If I create vars in a function, I can't use them directly in other functions. Thanks for explaining the term.redirect(mon), it's really helpful! :)/>
theoriginalbit #6
Posted 14 July 2013 - 08:45 AM
If I create vars in a function, I can't use them directly in other functions.
Exactly. Unless they're not local, and have been initialised before running the other functions.

Some more examples

--# a variable that is local to this code block (i.e. the program)
local some_var = 5

--# a variable that can be used by any other running code block (i.e. other programs or coroutines)
other_var = 6

--# a function that can only be used by this code block (program level)
local function some_func()
end

--# a function that can be used by any running block (other programs or routines)
function other_func()
end
This above knowledge is useful in the creation of APIs, as you can create functions that people can access and those that people cannot access.

One last piece of knowledge

local function one()
  some = 1
end

local function two()
  thing = 2
  print( some ) --# prints 1
  print( thing ) --# prints 2
  print( useful ) --# prints an empty line, useful is nil, it doesn't exist yet
  local useful = 5
  print( useful ) --# prints 5
end

local function three()
  print( some ) --# prints 1
  print( thing ) --# prints 2
  print( useful ) --# prints nothing, useful is nil, it doesn't exist anymore, local variables are destroyed after the scope they're in is finished as long as they're not referenced by something else
end

one()
two()
three()

Thanks for explaining the term.redirect(mon), it's really helpful! :)/>
No problems.