Var Scope and CFArgument


I've been developing ColdFusion applications for over ten years now. I wrote fairly good stuff. Some of my apps have pretty much just run since launch with no real issues. But they weren't the best they could be, because I was stuck behind the times. In the last three years or so, thanks to some reorganizations in our unit, attending CFUnited 2009, and I think most importantly having a great working partner, I've been working towards being a better coder and following more “best practices”.

One of those best practices is to “VAR scope” variables inside functions. This privatizes the variables in each function, reducing the chance for bleed over, particularly if you use like named variables (for example, many of our functions set up a return status structure of MyResults). By VAR scoping them, each variable will only be seen by that specific function. Without the VAR scope, the variables default to the variables scope, which is open to all functions and those functions can each modify them, which can cause unexpected results.

Putting a variable into the VAR scope is pretty easy, just preface it with VAR:

<cfset VAR myVariable = 1 />

All VAR scoped variables must be immediately after the last tag of your function. You can put comments in, of course, but no other sets or the like can go in until you are done. So I do it in all my functions. When while working on a new project, particularly as I began implementing our first service layer, I had an error come back that I was trying to declare a local variable twice! What? I checked the code again and again, but I was still confused.

<cffunction name="saveCoordinator" access="public" output="false" returntype="struct">
        <cfargument name="Coordinator" type="Coordinator" required="true" />

        <cfset VAR Coordinator = variables.coordinatorsDAO.save(Arguments.Coordinator) />

        <cfreturn Coordinator />
</cffunction><cfset VAR myVariable = 1 />

Some of you are already probably going “well duh, idiot” but it took me a few frustrating minutes to realize my error. Despite my years of experience, I hadn't run into it before because it just wasn't something that had happened before because it wasn't something I'd ever done, until I tried this service layer. The problem?

All cfargument variables are automatically VAR scoped! So with that code, I might as well have had something like:

<cffunction name="saveCoordinator" access="public" output="false" returntype="struct">
        <cfset VAR Coordinator = Arguments.MyCoordinator />
        <cfset VAR Coordinator = variables.coordinatorsDAO.save(Arguments.Coordinator) />
        <cfreturn Coordinator />
</cffunction><cfset VAR myVariable = 1 />

Now obviously this was a simple example with a simple solution, namely redoing the function like so:

<cffunction name="saveCoordinator" access="public" output="false" returntype="struct">
        <cfargument name="Coordinator" type="Coordinator" required="true" />
   
        <cfreturn variables.coordinatorsDAO.save(Arguments.Coordinator) />
</cffunction>

I am honestly surprised it hadn't happened before, particularly some functions I've built with 20 some arguments coming in. Conflict would seem to be inevitable, but maybe that's because most were built before I started VAR scoping and just haven't been updated yet. Suffice to say, if you get that error about local variables declared twice, but don't see a repeat in your set of VAR variables, make sure you don't have a repeat of that variable in the CFARGUMENT group.