Skip to main content
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Steve 'Cutter' Blades
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Steve 'Cutter' Blades ( @cutterbl )

Learning ColdFusion 8: Implicit Struct And Array Creation

By on
Tags:

One of the coolest features of ColdFusion 8 is its new implicit struct and array creation. For those of you who love Javascript, you will be used to seeing this type of struct definition:

<cfset objData = {
	Key1 = "Value1",
	Key2 = "Value2"
	} />

... and this type of array definition:

<cfset arrData = [
	"Value1",
	"Value2"
	] />

Prior to ColdFusion 8, you have to do the above definitions with a StructNew() (or ArrayNew( 1 )) and several CFSet tags. Clearly, this implicit creation is going to really whip the llama's ass... or is it?

Before I could really get to the bottom of how hard this was going to rock, I need to figure out how it worked, where it worked, and more importantly, where it did NOT work. First, let's test just the very basic implicit struct and array creation as we did above:

<!---
	Create the date plan using ColdFusion 8's
	new implicit struct creation.
--->
<cfset objDate = {
	Pickup = "7:45 PM",
	Dinner = "Outback Steak House",
	Dessert = "Cafe Lalo"
	} />

<!--- Dump out the data to see if it worked. --->
<cfdump
	var="#objDate#"
	label="Implicit Struct Creation Test"
	/>


<!---
	Create an array of movie times using
	ColdFusion 8's new implicit array creation.
--->
<cfset arrMovieTimes = [
	"7:00 PM",
	"9:15 PM",
	"11:14 PM"
	] />

<!--- Dump out the data to see if it worked. --->
<cfdump
	var="#arrMovieTimes#"
	label="Implicit Array Creation Test"
	/>

Running the above code, we get the following CFDump outputs:

ColdFusion 8 Implicit Struct Creation
ColdFusion 8 Implicit Array Creation

That worked quite nicely. But, let's face it, that's really basic. Let's start pushing the envelop a little bit. Let's try nesting our implicit struct and array construction. The ColdFusion 8 "What's New" documentation already says that this cannot be done, but I figured I would see that for myself:

<!---
	Now, let's recreate the date, except this time, we
	are going to combine the implicit struct creation
	with the implicit array creation.
--->
<cfset objDate = {
	Pickup = "7:45 PM",
	Dinner = "Outback Steak House",
	Movie = "28 Weeks Later",
	MovieTimes = [
		"7:00 PM",
		"9:15 PM",
		"11:14 PM"
		],
	Dessert = "Cafe Lalo"
	} />

As expected, this throws the ColdFusion parsing error:

Invalid CFML construct found on line 66 at column 18. ColdFusion was looking at the following text: {

Ok, that doesn't work. But, maybe it doesn't work because it was using a nested array construction; maybe it will work if we use an implicit struct creation instead:

<!---
	Now, let's recreate the date, except this time, we
	are going to combine the implicit struct creation
	with the implicit array creation.
--->
<cfset objDate = {
	Pickup = "7:45 PM",
	Dinner = "Outback Steak House",
	Movie = "28 Weeks Later",
	MovieTimes = {
		Time1 = "7:00 PM",
		Time2 = "9:15 PM",
		Time3 = "11:14 PM"
		},
	Dessert = "Cafe Lalo"
	} />

Nope. That gives us the same ColdFusion parsing error.

The beauty of a ColdFusion struct is that you can keep pumping key-value pairs into it and it will just overwrite any existing values. What happens if we do that same thing with implicit struct creation? In this next test, we are going to set the same key twice to see how it handles it:

<!---
	Let's recreate the date plan using ColdFusion 8's
	new implicit struct creation, but this time, we
	are going to define one of the keys twice to see
	how it reacts.
--->
<cfset objDate = {
	Pickup = "7:45 PM",
	Dinner = "Outback Steak House",
	Dessert = "Cafe Lalo",
	Dinner = "Ruby Fu's"
	} />

<!--- Dump out the data to see if it worked. --->
<cfdump
	var="#objDate#"
	label="Implicit Struct Creation Test"
	/>

Running the above code, we get the following CFDump output:

ColdFusion 8 Implicit Struct Creation With Duplicate Keys

As you can see, the value "Ruby Fu's" properly overwrote the original Dinner value of "Outback Steak House." Nicely done.

Now that we know implicit struct and array creation works on some basic level, let's see if we can evaluate strings that contain implicit struct and array creation. You never know when something like this might be useful:

<!---
	We know that we can use the implicit struct
	creation directly, but can we evaluate it as
	if it were a variable? Let's create a string
	that will represent our implicit struct.
--->
<cfset strStructure = "{ Name = 'Must Love Dogs', Time = '7:30 PM' }" />

<!---
	Now, let's try to evaluate the implicit structure
	creationg and save it in to the movie variable.
--->
<cfset objMovie = Evaluate( strStructure ) />

<!--- Dump out the data to see if it worked. --->
<cfdump
	var="#objDate#"
	label="Implicit Struct Evaluation Test"
	/>

When we try to run that code, we get the following ColdFusion error:

Invalid CFML construct found on line 1 at column 1. ColdFusion was looking at the following text: {

Ok, so no evaluation abilities.

Above, we discovered that we cannot have nested implicit struct creation, but the documentation says we can have nested structs - just not through implicit creation. Well, what happens if the nested structure is created through the use of a ColdFusion function? Remember our old-school function, StructCreate():

<cffunction
	name="StructCreate"
	access="public"
	returntype="struct"
	output="false"
	hint="Creates a struct based on the argument pairs.">

	<!--- Define the local scope. --->
	<cfset var LOCAL = StructNew() />

	<!--- Create the target struct. --->
	<cfset LOCAL.Struct = StructNew() />

	<!--- Loop over the arguments. --->
	<cfloop
		item="LOCAL.Key"
		collection="#ARGUMENTS#">

		<!--- Set the struct pair values. --->
		<cfset LOCAL.Struct[ LOCAL.Key ] = ARGUMENTS[ LOCAL.Key ] />

	</cfloop>

	<!--- Return the resultant struct. --->
	<cfreturn LOCAL.Struct />
</cffunction>

This ColdFusion user defined function (UDF) gives us the ability to create structures and give them initial values on the fly (this is essentially what implicit creation is doing). Let's see what happens if we use that function inside of an implicit struct creation:

<!---
	As the documentation states for this beta, we cannot
	nest implicit structs / arrays without an intermediary
	variable. However, what happens if we use an intermediar
	function call to create our structure? Let's try this
	again with a combination of ColdFusion 8's new implicit
	struct creation and our old-school StructCreate() UDF.
--->
<cfset objDate = {
	Pickup = "7:45 PM",
	Dinner = "Outback Steak House",
	Movie = StructCreate(
		Name = "28 Weeks Later",
		Time = "7:45 PM"
		),
	Dessert = "Cafe Lalo"
	} />


<!--- Dump out the data to see if it worked. --->
<cfdump
	var="#objDate#"
	label="Implicit Struct Creation / UDF Test"
	/>

Notice that the StructCreate() is being set as the value to a key in the implicit struct. Running the above code, we get the following CFDump output:

ColdFusion 8 Implicit Struct Creation With StructCreate() UDF

That worked quite nicely. And, it got me thinking; this StructCreate() method, while useful, might be improved with ColdFusion 8's implicit struct creation. Think about it - in this scenario, what are we really doing? The goal of StructCreate() UDF in this case is just to echo back the struct to overcome the limitations of implicit creation. Since we know we can create implicit arrays and structures on the fly, why not just create an Echo() UDF to act as the intermediary variable?

<cffunction
	name="Echo"
	access="public"
	returntype="any"
	output="false"
	hint="Just returns the first argument passed to it.">

	<cfreturn ARGUMENTS[ 1 ] />
</cffunction>

Notice that this UDF just returns back the first argument passed to it. What we are going to do is just use this as a wrapper to shield the parser from nested implicit variable creation:

<!---
	Now that we know that function calls can exist within
	the nest of ColdFusion 8's new implicit struct creation,
	we can use the Echo user defined function to really
	create some intricate structures with minimal effort.

	We are going to pass the implicit creation go the Echo
	function and have it just bounce back.
--->
<cfset objDate = {
	Pickup = "7:45 PM",
	Dinner = "Outback Steak House",
	Movie = Echo({
		Name = "28 Weeks Later",
		Time = "7:45 PM"
		}),
	Dessert = "Cafe Lalo"
	} />

<!--- Dump out the data to see if it worked. --->
<cfdump
	var="#objDate#"
	label="Implicit Struct Creation w/ Echo Test"
	/>

Notice that the Movie value is set to the return value of the Echo() UDF and to the Echo() UDF, we are passing an implicit struct. Since this worked with StructCreate(), it follows that it should work with this test. Unfortunately, this throws the following ColdFusion error:

Invalid CFML construct found on line 172 at column 25. ColdFusion was looking at the following text: {

As it turns out, you cannot pass an explicit struct or an array to a method call. You cannot even pass it if you give it a key:

<cfset objStruct = Echo(
	Value = { Foo = "Bar" }
	) />

I have to be honest here - this is very uncool. One of the most powerful features of implicit struct and array creation in other languages such as Javascript is the ability to, on the fly, create structures and pass them to functions. I am very disappointed that this does not work, and I think it really takes away from the usefulness of this feature. Hopefully this is just bug that will be fixed in the actual ColdFusion 8 product release.

So maybe you cannot pass implicit structs to a function, but can you at least pass them to attribute values:

<cfdump
	var="#{ Movie = 'Mixed Nuts', Time = '7:45 PM' }#"
	label="Implicit Attribute Test"
	/>

Running the above code throws the following ColdFusion error:

Invalid CFML construct found on line 233 at column 15. ColdFusion was looking at the following text: { The CFML compiler was processing The tag attribute var. A cfdump tag beginning on line 232, column 2.

Ugggg! Are you telling me I cannot even do that? Well wait, ColdFusion 8 introduced a new attribute - AttributeCollection - which acts in place of the rest of the tag's attributes (in an either-or fashion). Maybe I cannot use implicit struct creation with a standard attribute, but surely I can use it with the AttributeCollection attribute:

<cfdump
	attributecollection = "#{ var = 'Collection Test' }#"
	/>

Nope. This throws the same ColdFusion error. This is really disappointing. I mean, you can't use implicit creation with method calls and you can't use it with attribute values. This is starting to look much less like on-the-fly functionality.

The documentation states that we cannot store an implicit struct into an array index, but can we store it into an struct key:

<!---
	Now that we know that ColdFusion 8's new implicit
	struct creation works on a basic level, let's try
	to use it to set values into existing structs.
--->
<cfset objDate = {} />
<cfset objDate.Pickup = "7:45 PM" />
<cfset objDate.Dinner = "Outback Steak House" />
<cfset objDate.Movie = {
	Name = "28 Weeks Later",
	Time = "7:45 PM"
	} />
<cfset objDate.Dessert = "Cafe Lalo" />

<!--- Dump out the data to see if it worked. --->
<cfdump
	var="#objDate#"
	label="Implicit Struct Creation w/ Struct Set"
	/>

Running the above code, we get the following CFDump output:

ColdFusion 8 Implicit Struct Creation Stored Into Existing Struct Key

Ok so at least that works nicely. Now, the ColdFusion 8 What's New documentation (page 12) states that you "cannot assign an implicitly created structure to an array element," but I figured I would give it a shot just to see it fail for my own eyes:

<!---
	Even though the What's New In ColdFUsion 8 documentation
	says, that this is not possible, let's try to store an
	implicit struct into an array index.
--->
<cfset arrData = [] />
<cfset arrData[ 1 ] = { Movie = "Mixed Nuts", Time = "7:45 PM" } />


<cfdump
	var="#arrData#"
	label="Implicit Struct Creation w/ Array Set"
	/>

Running the above code, we get the following CFDump output:

ColdFusion 8 Implicit Struct Creation Stored Into Existing Array Index

Apparently this does work. This may just be a case of the documentation not being updated since earlier betas or something (this is my first playing around with CF8).

So, I have to say, ColdFusion 8's new implicit struct and array creation is very cool; however, after some deep evaluation here, I am thinking that it is not as orgasmic as I was hoping it would be. I think, no question, implicit struct and array creation should be compatible with method calls and attribute values - hands down, not up for discussion. If you look at how these features are used in other languages, this is the majority of use cases. Creating structs without having to use StructNew() is nice, but honestly, that is such a small part of how something like this should be used.

I want to give a HUGE thanks to HostMySite.com for making ColdFusion8 beta testing accounts available. That is just awesome and perfect for those of us who have bosses that don't think installing CF8 Beta is a priority (grumble grumble grumble).

Want to use code from this post? Check out the license.

Reader Comments

57 Comments

Great analysis!

These were just the tests I was hoping to run for myself soon. I have to agree with you that it would have been nice to have nesting for inline array and structure creation.

More significantly, the limitation on passing it into a method call is significant. I was hoping to limit creation of named variables for temporary use (that have to be var'ed).

This definitely takes the feature down from "One of the best new features" to "A handy feature".

15,643 Comments

@Steve,

Thanks. I am with you on that - in that it just is not as awesome as it could be. Handy is the right word.

@Tony,

Will do that right now.

15,643 Comments

@Rick,

Consider it done. I should really take a look at those forums; I have never really done anything with the Adobe forum before.

198 Comments

@Ben,

I think the "cannot assign an implicitly created structure to an array element" is intended to mean you can't do:

myArray = [
{some='thing', more='thing'},
{some='thing', more='thing'}
]

I personally was really excited when I first heard they were adding this feature. Maybe it's because of years doing heavy JS, but I find implicit declaration very clear and you can create some very large data sets, with pretty minimal code.

Also, as for you dynamic string evaluation sample, one thing to remember is you *can* convert a JSON string to CF natively. This would allow you to do something like:

<cfsavecontent variable="code">
[
{some: 'thing', more: 'thing'},
{some: 'thing', more: 'thing'}
]
</cfsavecontent>

<cfset myArray = deserializeJSON(code) />

NOTE: The above code is only for recreational use--please don't try to build code based on that sample. :)

Finally, I would really like to see them do the implicit declaration correctly. I'd rather not have it at all, then to have a poor implementation of it...

15,643 Comments

@Dan,

I have to look into this deserializeJSON() method. I have not used it before. I saw in the What's New documentation that they updated it (which I assume means it was part of CFMX 7???). It looks very cool, I will have to check it out.

As for the storing implicit things into an array, I think the documentation is just outdated. They are very specific in their sample code for this matter.

76 Comments

Nice run through, "glad" to see that it isn't a good feature afterall.

Basically what you went over means that the new feature to create Objects/Arrays literals is pointless as you can't do anything that you should be able to do with them. This was something that I was most most looking forward to aswell as the addition of proper operators like: ! && || < <= >= + == etc.

Additionally something else that has not been addressed is the fact that creating a Struct in this format: object = {var1 = "string", var2 = 1} is incorrect - as far as other languages are concerned anyway. It should be like this: object = {var1 : "string", var2 : 1} notice the colons instead of equal signs?

Any insight on if that is going to be rectified?

15,643 Comments

@Shuns,

Scoprio is still in Beta, so who knows what the final product will hold. I suspect that this is just about what is going to be delivered as this Beta is now public. But, I cannot really speak to this end as I have not been involved in the CF development process.

12 Comments

Nice write up. Nested structures and arrays would be nice.

But doing something like this:
* <cfdump
* attributecollection = "#{ var = 'Collection Test' }#"
* />

would actually be more code not less so I don't really see the point in that.

15,643 Comments

@Sam,

I was testing it with the CFDump tag, but you are right - why would ever pass an implicit object to a CFDump tag. I was thinking more for use with other tags, but if it doesn't work in CFDump, I figured it wouldn't work with any other tags.

12 Comments

@Ben -- Oh yeah, I thought you meant for any tag. In JavaScript it makes a lot of sense to pass in arguments/attributes/call them what you want in that style, it just does not for cf.

15,643 Comments

@Sam,

I agree; I cannot think of a very good use case of passing in an implicit struct to a tag, but it just feels like something that should work.

45 Comments

Is it "attributescollection"? I thought that was an pre-exising input to custom tags. I thought the new one was "argumentscollection". At least, that's what I wrote down in my note's from Ben Forta's presentation to my user group.

15,643 Comments

@Brad,

It is AttributeCollection (singular). The Whats New documentation states that it was names ArgumentsCollection in earlier beta / alpha, but this is no longer.

1 Comments

Yes we cannot have dynamic array of structs either. So this does not work
<cfset pages=[{name="Carrot",value=2},{name="Rabbit",value=3}>
but you can have an array of lists using new style array creation:
<cfset pages=["carrot,2","Rabbit,3"]>
I then wrote a function to convert an array of Lists to an array of Structs (based on cflib.StructOfListsToArrayOfStructs).
<pre>
function ListsToStructs(items){
var fieldCount = 0;
var fieldname = '';
var fieldnames = ['name','value'];
var itemCount = 0;
var itemIndex = 0;
var params = {};
var result = [];
var values = [];
var valueCount = 0;
var valueIndex = 0;
var valueSeparator = ',';

if(arrayLen(arguments) GT 1) fieldnames = listToArray(arguments[2] );
if(arrayLen(arguments) GT 2) valueSeparator = arguments[3];


fieldCount = ArrayLen(fieldnames);
itemCount = ArrayLen(items);
result = [];

for ( itemIndex=1; itemIndex LTE itemCount; itemIndex = itemIndex + 1)
{
values = ListToArray( items[ itemIndex ], valueSeparator );
valueCount = min( ArrayLen( values ), fieldCount );

params = {};
for ( valueIndex = 1; valueIndex LTE valueCount; valueIndex = valueIndex + 1 )
{
fieldname = fieldnames[ valueIndex ];
params[ fieldname ] = values[ valueIndex ];
}
arrayAppend( result, params );
}
return result;
}
</pre>

1 Comments

Hi Ben,
Thanks for the great analysis... These inputs have been very useful.

Meanwhile, you can also spend some time playing with the cfpdf/pdfforms tags.

Regards,
-ahamad,
Adobe CF Team.

16 Comments

Just to add to the problems of implicit variable decorations:

Using any operator as an implicit struct key throws an error.

So

<cfset myStruct = { And = "break" } />

Doesn't work. Throws error... as do OR, MOD, EQ, LT, etc...

Where as:

<cfset myStruct = StructNew() />
<cfset myStruct.And = "okay" />

is fine.

Adds a lot of validation to creating dynamic structures using this method.

I tried adding quotes to the Keys and that doesn't work either.

1 Comments

Education.com provides expert advice, features, columns, thousands of reference articles, and a community for parents of pre-school to high school students.

1 Comments

This sounds like a "too little too late" feature. CF implements features that other languages have had for decades, and still manage to botch it completely to the point of uselessness.

Frankly, your "CreateStruct" function is superior to the { } syntax in every way, other than being 10 characters more to type.

With your "CreateStruct" basically ALL of your tests would work, which they fail to do with the CF lame-ass "implicit creation".

CS(name='per', job = CS(title='programmer', salary=75000)) would work perfectly fine, while the CF-thing fails to work.

In Python, to take one random example, all of your tests would also work. Same for Javascript, Perl, Ruby, PHP, basically any scripting-language you care to compare with.

1 Comments

Thank you for saving me a few hours (or more!) trying to evaluate/create structs on the fly. I just hardwired my "answer", but figured that since I haven't really done anything of substance in CF since ver 5.0, I should investigate. Your run-through gave me all the answers & updates to know that "what's done is done!". I'm excited to explore Flex 3 ... wherein my future holds something along the lines of: 1) fetch data from DB
2) create object(s)
3) introspect the objects and map to a struct on the fly

Keep up the good work!
Mike

15,643 Comments

@Nick,

At least they are getting closer. With the ColdFusion 8 updater, the will *probably* be allowing nested array and struct creation. It's a step closer.

2 Comments

Hi,
Currently, nested struct/array creation is not supported for:
1. Passing implicit structures/arrays to functions calls.

This is NOT allowed
MyName = MyStruct({ First = "Adobe", Last = "ColdFusion"});

2. Returning implicit structures/arrays as values.

This is NOT allowed
<cfreturn { First = "Adobe", Last = "ColdFusion"}>

Also Nested Struct/Array creation is not supported as of CF8.0

Ahamad,
ADOBE CF Team

2 Comments

Hi,
With the CF8 updater 1(8.0.1), we support Implicit nested array/struct creation.

Here are a few simple examples.

<cfset array1 = [ ["10", "20"], ["30", "40"] ]>

<cfset struct1 = { str1 = {key1 = "10", key2 = "20"}, str2 = {key3 = "30", key4 = "40"} }>

1 Comments

I was frustrated with this same issue PLUS the way it uppercases the keys in a struct (I do a lot of remoting):

<cfset foo = {myCamelCaseKey="hello world"}/>

becomes:

foo.MYCAMELCASEKEY

So I went back to using my old standard:

<cffunction name="createStruct" access="public" returntype="struct">
<cfreturn arguments>
</cffunction>

Which IMHO is a great solution 'cause it respects case:

<cfset foo = createStruct( myCamelCaseKey = "hello" )/>

And you can use it to create pseudo-Arrays (Structs that behave like Arrays):

<cfset foo = createStruct( "One", "Two", "Three" )/>
<cfset ArrayAppend( foo, "Four" );

Thanks for the great post, just thought I would share...

1 Comments

i am working with coldfusion for design web site & data sources,
but i am a problem, please help me,

please tell me about this error in setings of data sources:

Unable to update the ColdFusion ODBC Server.
Timeout period expired without completion of C:\ColdFusion8\db\slserver54\admin\swcla.exe

16 Comments

With 8.01 I'm trying to create a nested structure based on postprocessing a query and dynamically creating the keys and the following works fine with a single level structure with objQry being a valid query. However when I try a nested structure by uncommenting the commented lines I get a 'Invalid CFML construct found' on the line where 'stItem[objQry.abiitmkey] = {'. Any ideas what I could do to fix this. I want to be able to reference
stItem[objQry.abiitmkey].stFY[objQry.fy].qty for instance when I am done.
---------
<cfif Not StructKeyExists(stItem, "#objQry.abiitmkey#")>
<cfscript>
stItem[objQry.abiitmkey] = {
abiitmkey = objQry.abiitmkey,
risk = objQry.risk,
/* stFY[objQry.fy] = { */
fy = 0,
qty = 0
/* } */
};
</cfscript>
</cfif>

--------

1 Comments

Maybe it supports nested arrays and structs, but this syntax is still not supported when using inline in a function call:

<cfset methodCall(["a","b"])>

returns "When using named parameters to a function, every parameter must have a name.".

If I give the argument a name in the call, I keep getting this error.
Indeed, as you say, very uncool.

@casey: I use your method a lot, but for arrays the order is not guaranteed just like that, which is what I need. Calling createStruct(a="x",b="y") does not always return x,y in that order. It does work if you call createStruct() without arguments and then put items in later. But then the benefit of an inline call is lost. But still, a very powerful feature to use the argumentcollection like that.

3 Comments

I was looking for a tutorial like this and thank you thank you thank you for sharing this great knowledge.
I have a tab delimited text file where I need to create an array where each array element is a structure.
Your example of using implicit struct make my code so easy and clean!
Thanks Ben!

50 Comments

I sort of fell into a gotcha with this cause I was writing a new app on CF9 Beta, and in a few lines of code I was passing implicit structures as function arguments. It all worked as expected, until I deployed to our CF8 staging server and started getting errors of course.

Glad to see they finally took care of that in the upcoming release!

15,643 Comments

@Jose,

Yeah, it's an update that has been long-time desired. I think minor updates like that are a huge part of what is making CF9 so awesome.

1 Comments

Love your blog. You always cover things in such detail. Thanks for the info about implicit struct creation. Would never have done it. We're on CF9 now but I would have reached for scructnew. Ciao.

3 Comments

Works:
<cfset local.rv = [iif(arguments.in.elementid,1,0)]>

Does not Work:
<cfset local.rv = [iif(arguments.in.elementid!=0,1,0)]>

Conclusion:
coldfusion sucks...

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel