Welcome!

ColdFusion Authors: Maureen O'Gara, Hovhannes Avoyan, Yakov Fain, Pat Romanski, Liz McMillan

Related Topics: ColdFusion

ColdFusion: Article

CFDJ Feature — ColdFusion Structures

Making applications more modular and efficient

By Reference Versus by Value
Objects and variables are passed by one of two ways: reference or value. When an object is passed by value, a new object is created that has the same value as the original. When an object is passed by reference, the new object is simply a pointer to the value of the original object stored in memory. Most of us are used to variables that are passed by value. For example:

<cfset BillingFirstName = "Selene" />
<cfset ShippingFirstName = BillingFirstName />
<cfset BillingFirstName = "Dave" />
<cfoutput>#ShippingFirstName# - #BillingFirstName#</cfoutput>

The output of this code would be "Selene - Dave" because the value of BillingFirstName - in this case "Selene" - is passed to ShippingFirstName as its value. Even after BillingFirstName is changed to "Dave" the value of ShippingFirstName doesn't change.

The same is not true for objects that are passed by reference. If the example above was passed by reference as opposed to value, the output would be "Dave - Dave" because the value of BillingFirstName wouldn't be copied to the value of ShippingFirstName, rather a reference (or pointer) to BillingFirstName would be saved to ShippingFirstName. This means that when the value of BillingFirstName changes, the value of ShippingFirstName is also changed because ShippingFirstName just points to the value of BillingFirstName.

A good example of this is the billing and shipping information stored for an online purchase. Typically, the purchaser fills out his billing information and the next page contains the same information pre-populated in the shipping form. The purchaser can modify any information and then proceed with the checkout process. The following code would take the information entered into the billing form and then copy it to the shipping structure:

<cfscript>
    Session.BillingStruct = StructNew();
    Session.BillingStruct.FirstName = Form.FirstName;
    Session.BillingStruct.LastName = FormLastName;
    Session.ShippingStruct = Session.BillingStruct;
</cfscript>

On the shipping information page, the form is populated with the information in the shipping structure, which is a reference to the billing structure. When the shipping information is posted, the structure can be updated:

<cfscript>
    Session.ShippingStruct.FirstName = Form.FirstName;
    Session.ShippingStruct.LastName = FormLastName;
</cfscript>

If the purchaser changed no information, there's no problem.

However, any changes made will actually be made to Session.BillingStruct since Session.ShippingStruct is just a pointer. That means the billing information may no longer be correct.

To avoid this potential pitfall, the StructCopy() function can be used:

<cfscript>
    Session.BillingStruct = StructNew();
    Session.BillingStruct.FirstName = Form.FirstName;
    Session.BillingStruct.LastName = FormLastName;
    Session.ShippingStruct = StructCopy(Session.BillingStruct);
</cfscript>

When StructCopy() is used, the new structure will no longer be a pointer to the existing one, rather it will be a duplicate of the original structure. If a change is now made to Session.ShippingStruct, the values in Session.BillingStruct won't be affected and vice-versa.

Looping Over a Structure
There are two easy ways to loop over structures in ColdFusion: using the cfloop tag and a for loop in cfscript:

<cfscript>
    BillingStruct = StructNew();
    BillingStruct.FirstName = "Selene";
    BillingStruct.LastName = "Bainum";

    for(key in BillingStruct) {
      writeOutput(key & " = " & BillingStruct [key] & "<br />");
    }
</cfscript>

<cfloop collection="#BillingStruct#" item="key">
    <cfoutput>#key# = #BillingStruct[key]#<br /></cfoutput>
</cfloop>

Both the for loop and the cfloop examples above will return exactly the same results. The for loop method is great if you're only performing actions in the loop that can be done in cfscript. The following example will copy all of the fields in a form post to another structure:

<cfparam name="Cart.BillingStruct" default="#StructNew()#" />
<cfscript>
    for(field in Form) {
      Cart.BillingStruct[field] = Form[field];
    }
</cfscript>

Why wouldn't you just set Cart.BillingStruct equal to StructCopy(Form) you ask? If Cart.BillingStruct already existed and had keys, the StructCopy() function would overwrite the existing structure, whereas looping over the form and setting each field individually retains any previously existing Cart.BillingStruct keys that may not exist in the Form structure.

Combining Arrays and Structures
Structures can be extremely useful when used in combination with other structures and arrays. While structures can only be one dimension, the value of a key can be an array or even another structure, thus appearing to be multi-dimensional.

Throughout this article I've referred to a Cart structure that would hold the information from a shopping cart. Listing 1 provides a peek at a fuller version of this structure.

The first part of this example just sets form variables that would be similar to those passed by a shopping cart. The second part of the example creates a complex structure of structures and arrays of structures to hold all the information. What can you do with this structure? Pass it to a function!

Structures with Components and Functions
One of the most useful applications for structures that I've found is using them in conjunction with ColdFusion Components (cfcs). One of the drawbacks with a component is declaring every possible argument that may be passed to a function. If you're creating a function to insert a record with 20 columns, you may have to declare 20 arguments. However, if you pass a structure of those 20 elements into the function, you only have to declare one argument - the structure! This is also very helpful when it comes to adding and removing values - you don't have to update your argument declarations and your function calls - you only have to update the elements in the structure. The drawback, however, is that you can't force a structure element to be required or of a certain type without additional logic - validation that declaring the arguments of a function lets you do quite easily.

Using the shopping cart example above, it would be very difficult - not to mention annoying - to pass all the individual arguments into a function. Instead, the example in Listing 1 shows how to call the function passing in the structure and how the function itself would process the structure:

While not a complete shopping cart processing example, you can see how you can take a complex structure and process it by accessing particular elements and looping over others dynamically. Structures like this greatly clean up as well as modularize your applications.

While it would be impossible to list all structure uses and functions in a single article, you should now know what you need to start using structures to help make your applications more modular and efficient.

More Stories By Selene Bainum

Selene Bainum is a software architect at INPUT.  She has been a ColdFusion and SQL developer for over 10 years and runs www.webtricks.com.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.