Variables in CFML; Assignment by Value and Reference

Assignment by Value

In almost all cases assignments in CFML are by value. In other words an assignment creates a copy of the value. The following code illustrates this:

<cfset foo = 3>
<cfset fee = foo>
<cfset foo = 4>

The end result of the following code is that foo holds the value "4" and fee holds the value "3". The second line made a copy of the then current value of foo, subsequent changes to foo are not reflected in fee. The two variables are completely independent of one another.

ColdFusion performs assignment by value for all variable types except structures and queries. When using the assignment operator ("=") these are passed by reference as described below.

Assignment by Reference

Assignment by reference is a very powerful, but often confusing aspect of CFML development with structures and queries. Unlike other data types structures and queries are not copied by value when using the equals ("=") sign, instead a reference or pointer to them is created. This reference can be thought of as a link to the original data.

The following code illustrates this:

<cfset foo = StructNew()>
<cfset foo.KeyOne = 3>
<cfset fee = foo>
<cfset foo.KeyOne = 4>

In this example the end values of both foo.KeyOne and fee.KeyOne are "4". The assignment in line three creates a link to foo from fee so that any changes made to one are reflected in the other. In effect fee becomes an alias for foo. To make a true copy of a structure you must use the StructCopy() or the Duplicate() functions. The following changes the above example so that foo and fee are totally independent:

<cfset foo = StructNew()>
<cfset foo.KeyOne = 3>
<cfset fee = Duplicate(foo)>

To properly use this feature you must first have an understanding of differences between StructCopy() and Duplicate(). StructCopy() will perform a copy of only the "top" structure. Any sub-structures contained within will be passed by reference. Duplicate(), on the other hand, does indeed copy the entire structure and all its children, no pointers are created. In common use unless you have a very good understanding of the ramifications of this we recommend that you always use Duplicate().

Assignment by reference may not appear useful at first glance but is actually immensely useful in certain contexts:

  • Passing a structure as a attribute to a custom tags creates a reference. Changes made to the reference within the tag will be automatically reflected in the target structure. This can eliminate some memory usage as the reference consumes less memory than the original data. Also there is no need to explicitly pass the data in and out of the tag using the CALLER scope. Lastly the reference can be passed into deeply nested custom tags easily.
  • References can be used as convenient shortcuts into large or difficult to access (heavily-nested) constructs. A reference such as "Application.CompanyData.States.MA.Departments.Sales" can be linked to "OurDepartments.Sales" for easier access.
  • References can link several structures (or sub-structures) and queries together into a single, logical unit.
  • References can be used to link variables into other scopes. For example you might determine if a templates input came from a form or from the URL and then assign the proper scope to "NewData" via NewDate = URL or NewData = Form. Variable scopes will be detailed later in the guide.

One important issue to understand is that references directly access the target structure. So if the target structure requires locking (because it's in the application, session, or server scopes) then the reference variable also requires locking. This topic is fully detailed in our Guide to Locking. Locking references can become complicated very quickly so it's generally recommended that only advanced developers create references to shared scopes.

16 Current Sessions; Time: 18:48:56 06-01-2009; Tick: 546