Using Dynamic Keys In ColdFusion 9's Implicit Struct Creation

Posted August 23, 2010 at 9:54 AM by Ben Nadel

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

Aug 23, 2010 at 10:20 AM // reply »
1 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.


Aug 23, 2010 at 10:25 AM // reply »
10,638 Comments

@Sergii,

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


Aug 23, 2010 at 10:32 AM // reply »
131 Comments

@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!


Aug 23, 2010 at 10:34 AM // reply »
10,638 Comments

@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.


Aug 23, 2010 at 10:45 AM // reply »
131 Comments

@Ben,

Exactly. No more:

girl = {};
girl["hair"] = "Brunette";
girl["name"] = "Tricia";

etc.


Aug 23, 2010 at 11:18 AM // reply »
10,638 Comments

@Jason,

Amen!


Aug 23, 2010 at 12:32 PM // reply »
69 Comments

@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.


Aug 23, 2010 at 6:00 PM // reply »
33 Comments

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.


Aug 23, 2010 at 7:36 PM // reply »
134 Comments

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 ).


Aug 23, 2010 at 8:58 PM // reply »
10,638 Comments

@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.


Sep 9, 2010 at 2:28 PM // reply »
14 Comments

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


Sep 9, 2010 at 2:30 PM // reply »
10,638 Comments

@Joshua,

ColdFusion just keeps getting better and better!


May 11, 2011 at 7:00 PM // reply »
12 Comments

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.



Post A Comment

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.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 3, 2012 at 10:49 PM
How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2
Wow this was really helpful! Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did: $ . ~/.bash_profile Otherwise, NPM won't be found. ... read »
Feb 3, 2012 at 10:14 PM
Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion
@Ben, Just wanted to let you know that pusher are soon to start limiting sizes on messages. This was the detail that came through in the Feb dispatch: "However, we will soon be limiting the s ... read »
Feb 3, 2012 at 5:05 PM
Regular Expressions Make CSV Parsing In ColdFusion So Much Easier (And Faster)
I tried using your RegEx in my C# program, but it was matching an extra empty-string at the end and so I would end up with an extra field that doesn't exist, so I changed it to this: (^|,)("(?: ... read »
Feb 3, 2012 at 3:47 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
Josh Cyr posted this on Twitter just a little bit ago. Thought it was appropriate. http://stackoverflow.com/questions/1619152/how-to-create-rest-urls-without-verbs/1619677#1619677 ... read »
Feb 3, 2012 at 2:28 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
@Michael, You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent a ... read »
Feb 3, 2012 at 2:04 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
To quote Jurassic Park: "Just because you can doesn't mean you should". I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if ... read »
Feb 3, 2012 at 1:10 PM
REST API Design Rulebook By Mark Masse
@Jordan, Yeah, WRML was created by Mark Masse (author of the book). I also found it to be a bit convoluted. I suppose it is intended to allow the Client to be able to programmaticaly respond to cha ... read »
Feb 3, 2012 at 1:08 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
@Jason, To be honest, I don't have good answers for that kinds of stuff. And, to the point, that is specifically why I *really* liked the REST API Design Rulebook by Mark Masse - he just cuts throu ... read »