cfpost extends='There.are.no.Pointers.in.ColdFusion'

Posted on March 7, 2007

I was responding to “CFC interaction and persistent scopes (newbie questions)” on the CFCDEV list and it turned into this post.

One of the many questions asked by the original poster was regarding passing one object into another. Nando posted this in reply:

“In reality, all that is passed is a reference to the object. CFAS creates a variable when you instantiate an object in memory, and when you give it some name in some scope, then it has a reference to that variable. CFCs are passed by reference.

Kelly Brown has a great post about how There are no Pointers in Coldfusion and I’d like to expand on that.

Basically the problem is that if you write

<cfset session.foo = "Hello" />
<cfset variables.foo = session.foo />
<cfset variables.foo = "Goodbye">

then the value of session.foo is also Goodbye. However, if you duplicate() the session variable, you can avoid this problem.

<cfset session.foo = "Hello" />
<cfset variables.foo = duplicate(session.foo) />
<cfset variables.foo = "Goodbye">

Now variables.foo = "Goodbye and session.foo is still Hello.

We can’t use duplicate() on objects (CFCs) yet and I’ve no idea when we ever will. This is why you have to be very careful when you’re injecting session objects into other objects.

I found we had a problem with exactly that today (the day before open beta of our new site. Joy!).

Another developer had injected a core session object into another object in order to pass along its arguments in one shot.

Application.cfc:onRequestStart()

<cflock ...>
  <!--- session.data is a bean --->
  <cfset request.data = session.data />
</cflock>

some.cfm

<cfset data = request.data />
<--- ... --->
<cfset moreData = createObject("component", "moreData").init()/>
<cfset moreDataDAO = createObject("component", "moreDataObj").init( DSN = request.DSN ) />
<cfset moreData.read( moreData = moreData, data = data )/>

moreDataDAO.cfc:read()

<cfset arguments.data.init( ... ) />
<!--- etc. --->

moreData extends data and since data already exists in session, the intent was to inject moreData with data, then call data.get*() inside moreData.init(). The problem is that he called data.init() before passing data into moreData.init().

So let’s follow the chain of references to see what happened:

session.data -> request.data -> variables.data -> arguments.data.init()

data.init() was called from inside the other object without passing in values for all the arguments of the init method. Whenever this process was run, the data bean stayed in session, but its contents were reverted to their default, empty values.

Fortunately it only took a few minutes to put a band-aid in place. A complete fix should be ready by the end of the week. I think this is an excellent example of how fragile applications can become when developers lose track of their data’s origins.

So how do you solve this problem? Instead of passing the data bean into moreData as a single argument, the init() method in moreData shoud add the arguments defined in data.init().

About the Author
Adrian J. Moreno

Adrian is an enterprise solution architect and full stack developer. Which stack depends on which system is on fire at the time. More information