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

So I have a conundrum...

Started by Savage_Me55iah, 25 December 2016 - 01:00 PM
Savage_Me55iah #1
Posted 25 December 2016 - 02:00 PM
I've been working on this program on and off for a few months and finally decided to test it out, the idea behind it is this would run/log/provide windows/basic functions for my other programs with a simple shell.run to add them to the coroutine list.

http://pastebin.com/5y35NCBX

Yes I know I've probably got some illegal loops and kinks in there but I'm still debugging it picking them out with each run, though there is one kink I've run into I wasn't expecting. I think I have overwritten a default function of ComputerCraft or something along that line, all my functions are written to return tables with example()[1] returning a boolean on if the function ran correctly and example()[2] returning the result(s)
but I'm getting "prog:194 vm error: java.lang.ArrayIndexOutOfBoundsException"

I isolated the booleanCheck function (meant to return any nil values as false) and ran that separately with no qualms but in the program:-

booleanCheck(false) : returns {true, false} - correct
booleanCheck(false)[2] : java.lang.ArrayIndexOutOfBoundsException - obviously not what I wanted
x = booleanCheck(false) : java.lang.ArrayIndexOutOfBoundsException - ditto

and it does the same with any other simple function that's unrelated to the program after I've run program once (eg. term.getSize())

so I'm a bit flummoxed, lost and only have a inkling of what I've done wrong.

Thanks in advance.
Lupus590 #2
Posted 25 December 2016 - 07:13 PM
This post says: http://www.computercraft.info/forums2/index.php?/topic/14531-read-this-post-before-asking-questions/
java.lang.ArrayIndexOutOfBoundsException: 256

This is frequently caused by using a function that calls itself to create an infinite loop. You should instead use an actual loop structure. Most commonly, for infinite loops, you would use `while true do` to begin the loop and `end` to end it. To exit the loop, you could use the `break` keyword. If you actually need to use recursive functions, you can use proper tail-calls where possible to avoid overflowing the stack. However, if all you need is an infinite loop, it is preferable to use an actual loop instead. Here is a simplified example of creating an infinite loop with recursion, and the same function with a proper tail-call:


--this function will throw the error
function printMany()
  print("text")
  sleep(0)
  printMany()
end

--this function will not
function printMany()
  print("text")
  sleep(0)
  return printMany()
end

--but you should do this instead, wherever you can.
function printMany()
  while true do
        print("text")
        sleep(0)
  end
end

Savage_Me55iah #3
Posted 26 December 2016 - 01:35 AM
Yes I know about infinite loops however I think you saw the error and skipped the rest.

The functions I tested it on don't have loops of any sort and considering the term.getSize() starts playing up too it indicates something else afoot.
they seem to run fine as long as I don't try to assigned the return values :- x = example() or example[2]
Bomb Bloke #4
Posted 26 December 2016 - 04:22 AM
Dunno if you're familiar with type(), but you certainly call tostring() a lot…

Actually you call a lot of stuff a lot - you've got a half billion redundant functions in there for the sole purpose of calling functions to do the real work. If you were tail-calling it wouldn't be so bad, but I suspect you're overflowing the function stack without even recursing. That's quite an effort… Why do you have all those dummy functions?!

See, CC's Java-side code sticks running functions in an array (the function stack), and only actively executes the one at the end. When a function is called, a new instance goes into the list, and the everything lower down halts until that new one returns (at which point it's removed, and the old function becomes the top one again). But if you're making more calls than you're performing returns, the number of function instances in the array starts to build up - the cap's 256 entries at once (which is a lot in this context), and you're hitting it.

I'm also not sure what to make of your coroutine-based code; you're making a ton of functions for the purposes of managing coroutines (one should do), then finally passing a table to parallel.waitForAny()? That function's a coroutine manager itself (either use that or your own manager, you don't need both), and only accepts function pointers (with which it'll build coroutines for you).
valithor #5
Posted 26 December 2016 - 05:03 AM
You do also have what appears to be a infinite loop in the program as well.

Here are the line numbers of the last 99 functions in the stack before it crashes (could have done the whole stack, but decided it really was not needed): http://www.pastebin.com/aLti414D

The top one is the most recent, and the bottom one is the oldest one.

List was generated with something similar to this:

ok,err = pcall(error,"",250)
if #err ~= 0 then --# there was something in the stack to error
  for i = 2, 100 do --# pcall will be 1, so grab everything else
	ok,err = pcall(error,"",i)
	h = fs.open("errors","a")
	h.writeLine(err)
	h.close()
  end
end
Edited on 26 December 2016 - 04:35 AM
Savage_Me55iah #6
Posted 26 December 2016 - 06:01 AM
@Valithor I'll have to borrow that code, definitely makes it easier to see where and how it's looped.

Dunno if you're familiar with type(), but you certainly call tostring() a lot…

Actually you call a lot of stuff a lot - you've got a half billion redundant functions in there for the sole purpose of calling functions to do the real work. If you were tail-calling it wouldn't be so bad, but I suspect you're overflowing the function stack without even recursing. That's quite an effort… Why do you have all those dummy functions?!

See, CC's Java-side code sticks running functions in an array (the function stack), and only actively executes the one at the end. When a function is called, a new instance goes into the list, and the everything lower down halts until that new one returns (at which point it's removed, and the old function becomes the top one again). But if you're making more calls than you're performing returns, the number of function instances in the array starts to build up - the cap's 256 entries at once (which is a lot in this context), and you're hitting it.

I'm also not sure what to make of your coroutine-based code; you're making a ton of functions for the purposes of managing coroutines (one should do), then finally passing a table to parallel.waitForAny()? That function's a coroutine manager itself (either use that or your own manager, you don't need both), and only accepts function pointers (with which it'll build coroutines for you).

Thanks Bomb Blokes, that does explain the problem and with the dummy functions I am calling x2 of the functions so the errors I got from my test was cause I overloaded the table of called functions and so my tests afterwards wouldn't have allowed me to add to that, and does explain why the loop error pointed towards a function that didn't have a loop in it. I knew there were loops and I thought to clear them out with each run but wasn't aware of that.

The dummies are an experiment, placeholders so I can put the functions in any order, I'll admit I got a little bit ambitious with that