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

Unexpected Behaviour In Loop

Started by Zudo, 02 September 2013 - 11:09 AM
Zudo #1
Posted 02 September 2013 - 01:09 PM

local safeprint = print

local function iprint(...)
args = {...}
safeprint("[System] [Init] ", unpack(args))
end

local function clear()
term.clear()
term.setCursorPos(1,1)
end

clear()

local initf = fs.list("/.melted/init")

for i = 1, #initf do
os.run({["print"] = iprint}, fs.combine("/.melted/init/", initf[i]))
end

I have two programs in /.melted/init, but only one is executing. Can anyone see where I am going wrong?
theoriginalbit #2
Posted 02 September 2013 - 01:46 PM
your program pauses at the first call of `os.run`… when the first program finishes it should run the second…
Zudo #3
Posted 03 September 2013 - 02:07 AM
Why would it pause though…?
theoriginalbit #4
Posted 03 September 2013 - 02:13 AM

function one()
  print("one")
end

function two()
  print("two")
end

one()
two()

Function two will not run until function one has completed. os.run doesn't add into a top level, it runs the supplied file.

This is the os.run implementation ( bad indentation by developers FTW! :P/> )


-- Install the rest of the OS api
function os.run( _tEnv, _sPath, ... )
	local tArgs = { ... }
	local fnFile, err = loadfile( _sPath )
	if fnFile then
		local tEnv = _tEnv
		--setmetatable( tEnv, { __index = function(t,k) return _G[k] end } )
setmetatable( tEnv, { __index = _G } )
		setfenv( fnFile, tEnv )
		local ok, err = pcall( function()
		 fnFile( unpack( tArgs ) )
		end )
		if not ok then
		 if err and err ~= "" then
		printError( err )
	   end
		 return false
		end
		return true
	end
	if err and err ~= "" then
printError( err )
end
	return false
end

This is why they do this for when running their shell and rednet.


-- Run the shell
local ok, err = pcall( function()
parallel.waitForAny(
  function()
	os.run( {}, "rom/programs/shell" )
  end,
  function()
	rednet.run()
  end )
end )

Try this code

local initf = fs.list("/.melted/init")

for i = 1, #initf do
  initf[i] = function() os.run({["print"] = iprint}, fs.combine("/.melted/init/", initf[i])) end
end

parallel.waitForAll( unpack(initf) )
Zudo #5
Posted 03 September 2013 - 02:14 AM
ok.. confusing…
theoriginalbit #6
Posted 03 September 2013 - 02:21 AM
ok.. confusing…
Ok what exactly about it is confusing, I'll attempt to answer it a little better for you.
Zudo #7
Posted 03 September 2013 - 02:21 AM
I tried that, and it didn't work.

parallel:22: melted:23: Expected string,string

Line 23 is this line:


initf[i] = function() os.run({["print"] = iprint}, fs.combine("/.melted/init/", initf[i])) end

Edit: The way os.run works is confusing, I only started using it properly yesterday.
theoriginalbit #8
Posted 03 September 2013 - 02:26 AM
parallel:22: melted:23: Expected string,string
I just tested it, and got it to work like so

local path = fs.combine("/.melted/init/", initf[i])
initf[i] = function() os.run({["print"] = iprint}, path) end

Edit: The way os.run works is confusing, I only started using it properly yesterday.
Ok do you know how shell.run works?
Zudo #9
Posted 03 September 2013 - 02:31 AM
Still not working…


Ok do you know how shell.run works?

Not really. :(/>
theoriginalbit #10
Posted 03 September 2013 - 02:47 AM
Still not working…
…………… ugh. remove the fs.combine, just put ""/.melted/init/"..initf" in the second argument of os.run… that should work, if it isn't you're not typing it right and OS run isn't getting the second argument…

Not really. :(/>
Ok… how can I simplify this…………. Ok got it (I hope)…

You know how when we turn on a computer, the shell is running, then when we run a program that program then takes over and we don't see the shell again until the program completes?

This is because the shell calls our program via os.run, just like if we were to do a function call.


local function one()
  while true do
	print("one")
	sleep(0)
  end
end

local function two()
  print("two")
end

two()
one()
two()

The function two runs the first time, then when function one runs, we cannot call function two for the second time until function one has completed. Or to do an example similar to what you're doing.


local funcs = {
  function() print("one") sleep(0.5) end,
  function() print("two") sleep(0.5) end,
  function() while true do print("haha! I have control now!") end end,
  function() print("four") end,
  function() print("five") end
}

for i = 1, #funcs do
  pcall( funcs[i] )
end

With the above code, "one" and "two" will print immediately, but from then on all we will see is "haha! I have control now!" and we will not see "four" or "five" printed until the third one is stopped by CC with the "too long without yielding" error (since I didn't have it yield).

The same applies for os.run… os.run will load a file and then run it, all control is given to that program that it's running and the program that called os.run must wait for the program to finish before it may continue. Just like what we experience in the shell; the shell won't run again until our program is finished running, because our program has control.

The main point of os.run is to be able to specify a custom environment for the program to run inside of. shell.run actually just calls os.run with the shell's environment.

EDIT:
Therefore, if we want multiple things to run at once with os.run, we do it like anything else, we use the parallel api. To put it in an example like the first one, we would change

two()
one()
two()
into

parallel.waitForAll( two, one, two )
which is something you should be familiar with or at least seen before.
Edited on 03 September 2013 - 12:50 AM
Zudo #11
Posted 03 September 2013 - 02:55 AM
OK, both programs are in the table, but only one runs. Here is my code:


local initf = fs.list("/.melted/init")

for i = 1, #initf do
local path = "/.melted/init/" ..  initf[i]
initf[i] = function() os.run({["print"] = iprint}, path) end
end

print(unpack(initf)) -- Just making sure
parallel.waitForAll(unpack(initf))
theoriginalbit #12
Posted 03 September 2013 - 03:03 AM
The second one should run after the first one yields.