This question came in today and I just had to answer it quickly: (Sorry to the 200 other people who have email in my queue!)
How do I return a value from a recursive function? This does not seem to work in cf. I'm basically walking up a hierarchy returning needed items when I find them.
Luckily s/he sent the code. The problem will probably jump out as soon as you see it:
<cffunction name="recursive" returntype="struct">
<cfargument name="id" type="numeric" required="yes" />
<cfset var stThing = structnew() />
<!--- do some lookup based on id --->
<cfif lookup succesful>
<cfreturn stThing />
<cfelse>
<!--- get parent id --->
<cfset recursive(parentid) />
</cfif>
</cffunction>
Let's trace this line by line to see where the error occurs.
- The first thing we do is create stThing as a new structure.
- Then we do a look up. This is the part of the code that is assumed.
- If the look up was successful, we return the value.
- If not.... and here comes the important part - we call the method again, but notice we don't set a value. Whenever you do, cfset foo(), which is allowed, you are basically running a function and ignoring the result.
So basically his code does call itself recursively, but each time the result gets "lost" in the ether and isn't returned to the user. If he changed the cfset to:
<cfreturn recursive(parentid)>
It should work correctly. Recursion is like sushi - you need to be very careful when preparing it or the end result is crap (or even better, a server that loops until it crashes).
Archived Comments
Obvious to you and I, but recursion caused a number of people to drop out of Computer Science in college. It seems to be a tough thing to get your head around. Where I go crazy is forking.
ha! yeah, recursion is a hard beast to tame. I once saw a proof in grad school proving that everything can be expressed as a recursive function. So, for instance, println("hello world"); can actually be expressed recursively...not worht the work to do so though, eh?
Recursion is like SHUSHI .. LOL... Good to know !
cffunction doesn't handle recursion for complex datatypes. UDF's do. Check the following code, with two test functions one defined as UDF, one as cffunction.
<cfscript>
function test(depth)
{
var i=ArrayNew(1);
i[1]=depth;
writeoutput("going deeper " & i[1] & " " & depth&"<br>");
if (depth lt 3)
test(depth+1);
writeoutput("i'm back " & i[1] & "<br>");
}
</cfscript>
<cffunction name="test2" output="Yes" returntype="any">
<cfargument name="depth" type="numeric" required="Yes">
<cfset i=ArrayNew(1)>
<cfset i[1]=depth>
<cfoutput>
going deeper #i[1]# #depth#<br>
<cfif depth lt 3>
<cfset test2(depth+1)>
</cfif>
i'm back #i[1]#<br>
</cfoutput>
</cffunction>
<cfset test(0)>
<br><br>
<cfset test2(0)>
This returns:
going deeper 0 0
going deeper 1 1
going deeper 2 2
going deeper 3 3
i'm back 3
i'm back 2
i'm back 1
i'm back 0
going deeper 0 0
going deeper 1 1
going deeper 2 2
going deeper 3 3
i'm back 3
i'm back 3
i'm back 3
i'm back 3
In the cffunction the array is overwritten. In UDF you can define complex variables locally, apparently in cffunctions you can't. With simple datatypes it works ok.
Jeoroen, you are in correct. The problem is that you forgot to use the var keyword in your cffunctione example. Change your cfset i = arraynew(1) to
cfset var i = arraynew(1)
and it will work fine. Var scoping is described in the docs and is very important.
OK. I didn't know you could do scoping like that outside cfscript. Thanks.