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

Can't end program using error() function in parallel? What alternative can I use?

Started by Bambel Boar, 05 January 2019 - 04:53 AM
Bambel Boar #1
Posted 05 January 2019 - 05:53 AM
Yes I'm pretty amateur at LUA and ComputerCraft but this is exactly what you expected the first line of this post to say, isn't it?

Jokes aside, the intention of this program is to be a simple chat. I've made the program so that you should be able to exit out of it without having to do Ctrl-T. I'm using 'error()' to quit the program instead. I've placed 'error()' in the function that detects whether or not the person entered "/exit" into the program, "/exit" being the command I chose for exiting the program.

So basically, typing "/exit" triggers 'error()'

In the following case, earlier in my chat program, using 'error()' to terminate the program works just fine. There are other instances of me using 'error()' in the program in order to terminate the program that are fundamentally the same (at least I believe they are) and they also work just fine.


function printUsage()
  print("Usage:")
  print("chat <modem side> <channel>")
  print("chat about")
end
if #args < 1 then
  printUsage()
  error()
end

The problem I have is typing "/exit" into the program does not cause the program to exit. (not the program above but the one at the end of the post)

When type "/exit" it continues the program as normal. At first I suspected the 'while true do' loop at line 47 was to blame. I isolated 'parallel.waitForAny' from the loop, removed the loop, then added 'print("ok")' at the end of the program to see if 'print("ok")' would be parsed even if I typed "/exit". If it did print on the screen "ok" even if I typed "/exit", that meant that the loop wasn't the reason my program didn't end. Alas, it printed "ok" on the screen even when I typed /exit.

The 'if' statement at line 16 is the logic that checks to see if the user inputted "/exit", and calls 'error()' if the user did. Along with calling 'error()' it also prints ("Chat exited.") and transmits boolean "false" through the modem channel. Those two functions work fine, despite 'error()' not working as expected, so I know this 'if' statement is not at fault. I tried adding print() after the 'error' in the same 'if' statement and that did not get parsed, which I think is important to note, but I'm not entirely sure if it's relevant because I think this reflects how error() works. Still, I know the 'if' statement is being parsed.

So now I believe 'parallel.waitForAny' at the end is the reason I can't use error() to terminate the program. Am I using error() wrong? How should I be terminating the program?

The following is the code from the same program as the code from above, but I shortened and modified it so that you only see the relevant bit. I commented out the loop at line 47 for the reason I stated above, being that I was testing to see if that loop caused the issue that I am having. I also numbered the lines which I know is not common practice but it parses fine and it helps me to explain what I'm talking about above.


1 modem.transmit(uChan,os.getComputerID(),true)
2
3 function help()
4   print("Commands:")
5   print("/help")
6   print("/exit")
7 end
8
9
10 function send()
11   -- if user inputted a command it will not transmit it by way of setting goodToSend to false
12   goodToSend = true
13   uInput = read()
14
15   --commands
16   if uInput == "/exit" then
17	 print("Chat exited")
18	 modem.transmit(uChan,os.getComputerID(),false)
19	 error() -- This is the error() I expected to terminate the program, but it doesn't.
20	 print("111") -- This isn't being parsed, most likely because of the error() before it. Important to note
21   end
22
23   if uInput == "/help" then
24	 help()
25	 goodToSend = false
26   end
27
28   --sends message
29   if goodToSend == true then
30	 modem.transmit(uChan,os.getComputerID(),uInput)
31   end
32 end
33
34 function receive()
35   event,side,freq,reID,reMessage,distance=os.pullEvent("modem_message")
36  
37   -- if reMessage is true or false it means that person joined or left, respectively 
38   if reMessage==true then
39	 print(reID.." joined the chat.")
40   elseif reMessage==false then
41	 print(reID.." left the chat.")
42   else
43	 print(reID..": "..reMessage)
44   end
45 end
46
47 --while true do
48   parallel.waitForAny(send,receive)
49 --end
50
51
52 print("ok")
Luca_S #2
Posted 05 January 2019 - 07:50 AM
I also numbered the lines which I know is not common practice but it parses fine and it helps me to explain what I'm talking about above.
If you need line numbers you can upload your code to pastebin and it will allow people to easily download your code to ComputerCraft if necessary.

Ending your program with error() is not a really good idea in most cases, for the usage case I would recommend something like this:

if #args < 1 then
  printUsage()
  return
end

Instead of putting the while loop around parallel.waitForAny, I would you recommend you that you put it in each function, like this:

function send()
  local bRunning = true
  while bRunning do
    -- Current send() code
  end
end
function receive()
  while true do
    -- Current receive() code
  end
end

By using this you can always exit the send function by using:

bRunning = false
Exerro #3
Posted 14 January 2019 - 04:16 PM
I don't know what's going on here. If "Chat exited" is being printed, and "111" isn't, then you know that the `error()` call is ending the coroutine. From the source of parallel.waitForAny (notably line 30), if a coroutine errors, the error should propagate, so the fact that you're seeing "ok" is very weird.

I've tested a modified version of your code on ccemux:
Spoiler

function send()
  local uInput = read()
  --commands
  if uInput == "/exit" then
	  print("Chat exited")
	  error() -- This is the error() I expected to terminate the program, but it doesn't.
	  print("111") -- This isn't being parsed, most likely because of the error() before it. Important to note
  end
end
function receive()
  while true do -- an infinite, yielding loop so we know that receive will never terminate
   os.pullEventRaw()
  end
end
--while true do
  parallel.waitForAny(send,receive)
--end
print("ok")

and it works as expected…


Maybe upload the full code to pastebin? Also, what version of CC are you using, as there may be differences in the parallel API…?

It's also worth noting that error() generally isn't used to end programs, and a conditional loop like what Luca_S suggested is usually better. Doesn't matter too much though. Whatever works.