ColdFusion Zeus POTW: CallStack

This post is more than 2 years old.

One of the new language additions to ColdFusion Zeus is the ability to get the current callstack. If that sounds Greek to you, it's simply the ability for a function to know who call it, who called that guy, and so on. It sounds confusing, but a few quick examples will help.

In our first example, I've got a call to a UDF that calls another UDF. That UDF runs one of the two new functions introduced in this blog post, callStackGet.

<cfscript> function top() { return child(); }

function child() { return callStackGet(); } </cfscript>

<cfdump var="#top()#">

callStackGet returns an array of "invokers", or basically, how in the heck did we get here. Looking at the code it's easy enough to tell that child was called by top, and top was called by our cfdump. When displayed, this is what we get.

Notice the array is ordered from most immediate to the final originator of the caller. Also note that the function is labelled where appropriate. How about a slightly more complex example? Consider the code below.

<cfscript> function grandparent() { return parent(); }

function parent() { return child(); }

function child() { return new some().test(); } </cfscript>

<cfdump var="#grandparent()#">

This is similar to our earlier code, but now child is invoking a CFC as well. Here is some.cfc.

component {

function test() {
	return callStackGet();
}

}

And the result...

As expected, it picks up on the different file in the CFC.

Another option is callstackDump. callstackDump returns a string based version of the callstack. It supports logging to a file, logging to console, or simply printing to the browser. Here's a modified form of the CFM we last tested with.

<cfscript> function grandparent() { return parent(); }

function parent() { callstackDump(expandPath("./callstack.log")); callstackDump("browser"); return child(); }

function child() { return new some().test(); } </cfscript>

<cfdump var="#grandparent()#">

Notice I've added two calls to callstackDump. Most likely, this is a more real world example as you won't probably ever return a callstack to the user. Here's an example of how it prints to my browser.

And there you have it folks. I'll be posting another Zeus preview before the Christmas break.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Ryan Vikander posted on 12/19/2011 at 8:55 PM

This is my favorite new feature so far! Can't wait to use this.

Comment 2 by Steve Bryant posted on 12/19/2011 at 10:39 PM

I'm with Ryan. I have been wanting this for a long time. To me, this is a real reason to upgrade.

Comment 3 by Raymond Camden posted on 12/19/2011 at 10:45 PM

Cool to hear you guys like this!

Comment 4 by Sanoop posted on 12/20/2011 at 3:10 PM

Great! I like the stack trace.

I wish both the function names replaced with each other.
callstackDump() name should be callStackGet() and callStackGet() name should be callstackDump()

Comment 5 by Ben Nadel posted on 12/20/2011 at 7:02 PM

@Ray,

Does the name of the function listed depend on what it was named in the file? Or, what it was named at runtime (ie. is it the value that getFunctionCalledName() would return within a given function)?

Comment 6 by Raymond Camden posted on 12/20/2011 at 7:19 PM

Under most circumstances it would be the same, right? Or are you talking about a case where you create a copy of a UDF/method? If you can give me an easy test, I can run it and tell you.

Comment 7 by Ben Nadel posted on 12/20/2011 at 7:25 PM

Yeah, mostly the same; just wondering how it would work if I had copies of a method reference. Imagine I had a method that was a generic getter:

function getXYZ():
var name = getFunctionCalledName();
var prop = reReplace( name, "^get", "", "one" );
return( variables[ prop ] );

The, I could have something like this in my CFC:

this.getName = this.getDOB = this.getDateCreated = this.getXYZ;

I'm not saying I would do that, especially now that we have synthesized accessors; but, just curious what name would be returned in the callstack.

Comment 8 by Raymond Camden posted on 12/20/2011 at 7:26 PM

If you could ping me direct via email with code I could run, I'll drop in callStackDump and tell you.

Comment 9 by Ben Nadel posted on 12/20/2011 at 7:47 PM

Done :)

Comment 10 by Raymond Camden posted on 12/20/2011 at 7:50 PM

So I tested Ben's code. It shows that we report the REAL name of the function, not the function it was called as. Is that a bug? I have NO idea. Yall decide. ;)

Comment 11 by Atan posted on 12/21/2011 at 2:20 PM

+1

Comment 12 by Michael Horne posted on 1/19/2012 at 12:18 PM

Just read this.
Very similar to the trace() function that is floating about as a UDF. However, that doesn't make it any less welcome! Finally, easy child-parent based debugging!

Having said that... CFSCRIPT... Never have liked it! As much as I appreciate trying to homogenise the syntax of CF with JS and others, in my mind it still makes code more difficult to read and still has differences to other languages, so the problem still remains - my point being I still prefer the tag-based CF because it looks different to, for example JS, so there's no confusion when looking at code.

It's very early, so that may have been gibberish!

Comment 13 by Raymond Camden posted on 1/19/2012 at 8:24 PM

@Michael: I only use all script in my CFCs, which won't have JS or HTML in them so there is no chance of confusion. I definitely still use tag based CF all the time.