« The Candidates on Science Issues | Main | Mathematics Calendar 2005 »

Learning OOP in Flash: trouble with recursive method

Looking for a debugging puzzle? I'm stumped. When I try to use this method (a Class' method) to recursively call itself, I get a NAN returned instead of a number. Not only does it return NAN, but it keeps running down the code instead of exiting.

code and sample trace output in extended entry

Much of this should be looped, but I wrote it out to help me pinpoint the problem.

I want the numbers 1 through 4 to be distributed uniquely among 5 "rows". One row has it's own value, and we don't have to worry about that here.

First the method generates a random number between 1 and 4.

Then, it tests if this number is already in an array of numbers called _multiples. This information is saved as a local variable with true-false value for each "row".

Then, I loop through the numbers in _multiples, and if one matches my new number I'm supposed to start over again and call the method recursively. If my new number isn't in the _multiples array, then I add it and move on to the next row, returning the new number and exiting the method.

function getMultiple(i):Number{

trace("get multiple");

/*
Note to self: October 21, 2004
I'm getting an error with this when I test it:
When this function is recursively called, I end up with an NAN
for the ratio this is a multiple for.

It appears that the return statement is not causing an exit from
the function, as I would expect it to. Ugh!
*/

// get random number between 1 and 4, to use as multiple

var n = (Math.floor(Math.random()*4)) + 1;

// test if new number is already used as a multiple of base ratio,
// and get new nummber if needed

var tf0 = (n == _multiples[0]);
var tf1 = (n == _multiples[1]);
var tf2 = (n == _multiples[2]);
var tf3 = (n == _multiples[3]);
var tf4 = (n == _multiples[4]);

trace("row:" + i + " n:" + n + " m[0]:" + _multiples[0] + " n=m[0]? " + tf0);
trace("row:" + i + " n:" + n + " m[1]:" + _multiples[1] + " n=m[1]? " + tf1);
trace("row:" + i + " n:" + n + " m[2]:" + _multiples[2] + " n=m[2]? " + tf2);
trace("row:" + i + " n:" + n + " m[3]:" + _multiples[3] + " n=m[3]? " + tf3);
trace("row:" + i + " n:" + n + " m[4]:" + _multiples[4] + " n=m[4]? " + tf4);



if (tf0 == true){
trace("try again");
this.getMultiple(i);
} else if (tf1 == true){
trace("try again");
this.getMultiple(i);
} else if (tf2 == true){
trace("try again");
this.getMultiple(i);
} else if (tf3 == true){
trace("try again");
this.getMultiple(i);
} else if (tf4 == true){
trace("try again");
this.getMultiple(i);
} else {
// save number to array that holds all multiples

_multiples.push(Number(n));
return n;
}

}

Sample Trace Output:

case unique
get multiple
row:1 n:2 m[0]:undefined n=m[0]? false
row:1 n:2 m[1]:undefined n=m[1]? false
row:1 n:2 m[2]:undefined n=m[2]? false
row:1 n:2 m[3]:undefined n=m[3]? false
row:1 n:2 m[4]:undefined n=m[4]? false
get multiple
row:2 n:3 m[0]:2 n=m[0]? false
row:2 n:3 m[1]:undefined n=m[1]? false
row:2 n:3 m[2]:undefined n=m[2]? false
row:2 n:3 m[3]:undefined n=m[3]? false
row:2 n:3 m[4]:undefined n=m[4]? false
get multiple
row:4 n:1 m[0]:2 n=m[0]? false
row:4 n:1 m[1]:3 n=m[1]? false
row:4 n:1 m[2]:undefined n=m[2]? false
row:4 n:1 m[3]:undefined n=m[3]? false
row:4 n:1 m[4]:undefined n=m[4]? false
get multiple
row:5 n:3 m[0]:2 n=m[0]? false
row:5 n:3 m[1]:3 n=m[1]? true
row:5 n:3 m[2]:1 n=m[2]? false
row:5 n:3 m[3]:undefined n=m[3]? false
row:5 n:3 m[4]:undefined n=m[4]? false
try again
get multiple
row:5 n:4 m[0]:2 n=m[0]? false
row:5 n:4 m[1]:3 n=m[1]? false
row:5 n:4 m[2]:1 n=m[2]? false
row:5 n:4 m[3]:undefined n=m[3]? false
row:5 n:4 m[4]:undefined n=m[4]? false
correct row: 3
ratio1 : 2,2
ratio2 : 3,3
ratio3 : 4,5
ratio4 : 1,1
ratio5 : NaN,NaN

Comments

The elements of your _multiples array are of type Object ... try casting them to Number(_multiples[0]) in your boolean tests.

I'd run into the same issue recently, and found that forcing the object to be a Number sorted it for me.
I hoped I was going to be smart and be first to suggest that, but Richard beat me to it. Grrrrr!

Yep, I've tried. Unfortunately it didn't help :(

Trying something else now

NAN = Not A Number... ;)

Ok.. maybe I'n not smart enough to help ;/

:-) That's the root of the problem, Irvine...that for some reason the the method isn't returning a number when it's called recursively.

When it only runs once, it returns a number, but as soon as it calls itself it no longer returns a number.

Well, turns out it was a pretty minor thing (and therefore easy to miss)... getMultiple should return a Number but when it calls itself it just calls itself without using the result of called getMultiple as a result itself... So in the code above 'this.getMultiple(i);' should be 'return this.getMultiple(i);'.. Et voila.. Magic! *phew*...

Thanks Edwin! That did it...I can't believe I didn't see it.