Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at NCDevCon 2011 (Raleigh, NC) with:

Using Dynamic Keys In ColdFusion 9's Implicit Struct Creation

By Ben Nadel on
Tags: ColdFusion

At CFUNITED 2010, I attended Elliott Sprehn's presentation, "I Bet You Didn't Know You Could Do That With ColdFusion." In his code samples, I saw something that I had never seen before - he was using quoted-keys in his ColdFusion implicit struct creation. In ColdFusion 8, this definitely causes a parsing error at compile time. But, it looks like it's finally available in ColdFusion 9.

To test this, I put together a simple, implicit struct demo using quoted keys:

  • <!---
  • Create a girl object. Notice that the keys in the implicit
  • struct are being quoted.
  • --->
  • <cfset girl = {
  • "name" = "Tricia",
  • "hair" = "Brunette"
  • } />
  •  
  • <!--- Output the girl. --->
  • <cfdump
  • var="#girl#"
  • label="Girl"
  • />

As you can see, there's nothing too tricky going on here - rather than using the literal keys, I've put quotes around the implicit struct keys. First, I ran this in ColdFusion 8 just to confirm that it did, indeed, cause a parsing error... and it did:

Invalid CFML construct found on line 8 at column 15. ColdFusion was looking at the following text:
{
The CFML compiler was processing: A cfset tag beginning on line 8, column 2.

Then, I ran this in ColdFusion 9. To my delight, it worked:

 
 
 
 
 
 
ColdFusion 9 Allows Implicit Struct Keys To Be Quoted. 
 
 
 

Now that ColdFusion 9 allows quoted keys within its implicit struct creation, we can start to use dynamic keys in our implicit struct creation:

  • <!---
  • Set key mappings that we are going to use to dynamically create
  • the succeeding implicit struct.
  • --->
  • <cfset keys = {
  • hair = "hairColor",
  • name = "name"
  • } />
  •  
  • <!---
  • Create a girl object using dynamically mapped names. Because the
  • keys are being quoted, we can now create dynamic names.
  • --->
  • <cfset girl = {
  • "#keys.name#" = "Tricia",
  • "#keys.hair#" = "Brunette"
  • } />
  •  
  • <!--- Output the girl. --->
  • <cfdump
  • var="#girl#"
  • label="Girl"
  • />

I know this is a completely trite example; but, it totally works:

 
 
 
 
 
 
Now That ColdFusion 9 Allows Implicit Struct Keys To Be Quoted, It Means We Can Use Dyamic Keys. 
 
 
 

As you can see, the key "hair" was successfully mapped to "hairColor" and the key "name" was successfully mapped to "name." Again, this is a silly example; however, I knew that this type of programming caused an error in ColdFusion 8 because there were a number of times in which dynamic keys would have been awesome in the context of implicit struct creation!

The Following Holds No Value (Skip If You Want)

Sometimes, when I create demos like this, I like to write something that I know will cause an error; then, I add to it until the error is gone. I approach testing in this way so as to ensure that I actually know which part of the code causes the desired outcome.

When I was putting the above example together, I started out with this code:

  • <!---
  • Set key mappings that we are going to use to dynamically create
  • the succeeding implicit struct.
  • --->
  • <cfset keys = {
  • hair = "hairColor",
  • name = "name"
  • } />
  •  
  • <!--- Create a girl object using dynamically mapped names. --->
  • <cfset girl = {
  • keys.name = "Tricia",
  • keys.hair = "Brunette"
  • } />
  •  
  • <!--- Output the girl. --->
  • <cfdump
  • var="#girl#"
  • label="Girl"
  • />

As you can see here, I am using dynamic keys; but, I am not quoting the keys. Like I said before, I expected this code to error (and then I would add the quotes and have it work). But, ColdFusion faked me out and actually ran this code without error:

 
 
 
 
 
 
Strange Implicit Struct Creation With Nested Structs. 
 
 
 

I am not sure exactly how this is being processed. It looks like it is actually creating the Keys struct inside of the implicit struct creation (using ColdFusion's dynamic struct generation logic) and then, it's storing that Keys struct inside of the Girl using the "Keys" key.

After seeing this work, I tried to run the following:

  • <!---
  • Delete any existing keys struct (all these damoes are actually
  • on the same code page, shhhh).
  • --->
  • <cfset structDelete( variables, "keys" ) />
  •  
  • <!--- Create the Girl struct with a totally new key struct. --->
  • <cfset girl = {
  • keys.name = "Tricia",
  • keys.hair = "Blonde"
  • } />
  •  
  • <!--- Output the girl. --->
  • <cfdump
  • var="#girl#"
  • label="Girl"
  • />

This approach was just to make sure nothing tricky was going on. Since all of my code samples are actually on the same page, I wanted to make sure that no pre-existing objects were causing unintended behavior.

Not only did this code work in ColdFusion 9, this particular portion of the demo also worked in ColdFusion 8. I'm tempted to say that this is the expected behavior since ColdFusion will dynamically generate structs to house non-existent key-paths; however, this just feels very weird (I never liked the fact that this behavior existed in ColdFusion in the first place - it seems like a very sloppy way to create data structures).

So anyway, ignoring the latter half of this post, it's just exciting that ColdFusion 9 finally allows us to use dynamic keys in implicit struct creation. This is why I make it a habit to never miss an Elliott Sprehn presentation.




Reader Comments

Oh yes, maybe in CF10 they'll add the JavaScript-style syntax, supported by Railo for ages:

<cfset girl = {"name": "Tricia", "hair": "Blonde" } />

For some reason I like this one most of all.

Reply to this Comment

@Sergii,

I wonder, can you create dynamic keys in Javascript JSON? I don't think that's something that I have ever tried before.

Reply to this Comment

@Ben, this is cool because it maintains the case of the keys.

girl = { hair="Brunette", name="Tricia" };

Output that and you get
girl
HAIR | Brunette
NAME | Tricia

But with

girl = { "hair"="Brunette", "name"="Tricia" };

It looks like it maintains case for you:

girl
hair | Brunette
name | Tricia

Now, that's handy!

Reply to this Comment

@Jason,

Yes - excellent point! I didn't notice that in the CFDump output, but you are completely right. That is very exciting, especially for anything that has to interact with JSON/Javascript serialization.

Reply to this Comment

@Ben. Yes, you can use quoted names in JavaScript's "object initializer" syntax (ECMA's name for object literals). You can also use numeric literals as names, believe it or not. Only the serialized-into-a-string JSON format requires quotedstring:quotedstring, not JS itself. So if you're building a JSON string manually, you could say:

var myJSON = '{"'
+ document.myform.name.value
+ '":"'
+ document.myform.hair.value
+ '"}';

Voila, a dynamic JSON name, which you could then JSON.parse() into an object based on form inputs.

Were you wondering whether or not you could do that with an object initializer / object literal? If so, I can tell you for a fact that this does NOT work in Firefox, because I just tried:

var girlname = "Alessandra Ambrosio";
var girlhair = "silky brown";
var girl = {girlname:girlhair};

At the end of doing this, the property girl["Alessandra Ambrosio"] will not exist. What you will get instead is girl["girlname"] or girl.girlname being equal to "silky brown". In other words, JS will do expression evaluation to the right of the colon in an object initializer / literal, but not on the left of the colon. Whatever's to the left of the colon is essentially treated as if it were in quotes (unless it's a number).

So although "JSON" literally means "JavaScript Object Notation", that name is not literally true. Object initializers, also known as object literals, are different in ways other than just the quotedstring:quotedstring restriction in JSON.

P.S.: I'm glad I ran the Alessandra experiment for this post, because I didn't previously know whether or not a string expression to the left of the colon would work.

Reply to this Comment

The case thing is also VERY handy when returning an object to flex, not an issue when using a value object, but returning a regular struct can be a pain, I hate using:
result={};
result["Hair"]="brown";
result["Eyes"]="blue";

to keep the case the way i want.

Yet 1 more reason to upgrade.

Any big gotchas upgrading 8->9?
Would like to be prepared for anything like the cfform scriptsrc issue with 6->7.

Reply to this Comment

I feel like what's blatantly missing from this is the ability to use colons instead of equals signs.

<cfset vanessa = { "freakyHot": true, "freakySensitiveWhenYouAskIfHerRoommateWouldBeOnboardWithThisMakeout": true } />

With how cousin CF is to JS to me I regularly type colons in my CF without even thinking about it and it doesn't register until I see the error. Gimme both please ( though secretly I'll never use the equals signs again ).

Reply to this Comment

@Steve,

It would be neat in Javascript; but, for some reason, it's never been something that I've ever really thought about. Definitely in ColdFusion, however, it is something that I would like a lot.

@David,

Good point with the FLEX stuff; I haven't done too much with FLEX. As far as moving from CF8 to CF9, I haven't noticed anything too crazy yet. I only use CF9 in local testing just yet, so I don't have any real field experience with an upgrade. But so far, no red flags.

@David Mc,

Ha ha ha, word up - I definitely type colon accidentally and end up with a juice syntax error. Would be cool to have colon-syntax.

Reply to this Comment

Cool. This just feels natural. That's great when the language gets to a point where stuff just feels right how it's working. :-)

Reply to this Comment

Hi Ben,

Love the idea of dynamic keys in an implicit structure.

However, I'm trying to take this one further by using a LOOP within my key creation. IS this possible? I think possibly not.

The dynamic examples you have shown are variables that you otherwise know about, but I'm trying (or at least want to) loop a query columnList to create dynamic keys at the implicit creation stage.

Hope that makes sense. Consider this:

<cfquery name="createNodeStructure">
SELECT *
FROM node
</cfquery>

<cfset variables.nodeStructure = {} />

<cfloop query="createNodeStructure">

<cfset nodeStructure[createNodeStructure.nodeID] = {} />

<cfloop index="i" list="#createNodeStructure.columnList#">
<cfset nodeStructure[createNodeStructure.nodeID][i] = createNodeStructure[i] />
</cfloop>

</cfloop>

Instead of having that second CFLOOP, is there any way to have that WITHIN the braces "{}" ?

Call me crazy but hey!

Love your blog as ever by the way.

Thanks,
Michael.

Reply to this Comment

CFSET requestData = StructNew()>

cfset ccount = 0>
CFQUERY>

<!-- retrieve order data--->

/CFQUERY>
CFSET variable[requestData.L_NAME & ccount] = "#description#">
CFSET variable[requestData.L_AMT & ccount] ="#trim(numberFormat(eachescost,99999.99))#">
CFSET variable[requestData.L_QTY & ccount] = "#quantity#">
CFSET variable[requestData.L_NUMBER & ccount] = "#itemnumber#">
CFSET variable[requestData.L_DESC & ccount] = " #size#">
cfset ccount = ccount + 1>
/cfloop>

cfdump var="#requestData#>

does not populate the structure with the dynamic names. so why not?

any suggestions?

Reply to this Comment

yes just my typo sorry. for some reason its not making it into the requestdata structure. not sure why i do not get any errors when i run it.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.