ColdFusion introduced CFML struct and array literals in CF 8. They sucked. Assignment only, no nesting, and the use of '=' for key-name pairs instead of ':', like every other language including other parts of CFML. CF 8.0.1 fixed the nesting issue, but not the others. I've been trying to figure out why it's an assignment-only construct since CF 8 was released, and today I figured it out. It's stupid. Take this code (which fails on CF8):
<cfset s = "cat,dog,bird" />
<cfset s = {
first = listFirst(s),
rest = listRest(s)
}/>
If you were to convert that to the old non-struct-literal syntax, it'd probably look like this:
<cfset s = "cat,dog,bird" />
<cfset temp = structNew() />
<cfset temp.first = listFirst(s) />
<cfset temp.rest = listRest(s) />
<cfset s = temp />
That's what Railo does (or the equivalent), but ColdFusion evaluates it like this:
<cfset s = "cat,dog,bird" />
<cfset s = structNew() />
<cfset s.first = listFirst(s) />
<cfset s.rest = listRest(s) />
This will obviously fail, because ColdFusion is reassigning the 's' variable too early in the process. In most cases it doesn't matter, but not all cases. Worse, it doesn't give you a useful error. Instead, it says "Complex object types cannot be converted to simple values", which while accurate, is totally perplexing if you consider the original snippet.
Note that this is a ColdFusion problem, not a CFML one. Railo compiles it correctly (and it doesn't share the assignment-only requirement either). OBD doesn't support literals at the moment.
Edit 2009/04/07: revised some text slightly.
Hey Barney, Are you providing these notes to Adobe?
Sami,
Absolutely. Everything I bitch about goes into the wish form (and god knows where after that). I'm anxiously waiting for them to get JIRA set up. It's quite nice to be able to follow resolution progress with Railo, without having to wait to read release notes, especially if there's ambiguity in the submission.
Great to hear that.
I think the wish list gets broadcast to the whole development team, which is both good and bad, because I'm not sure if any one person takes ownership of it.
Waiting for the bug base as well. But, once the committees are setup, we can barrage members as well who are managing the specific area we find issues with.
Barney, are you sure those code fragments are right? The third fragment seems to assign to s and then overwrite it with an empty struct. I'm not quite sure what point you're trying to make here. Could you clarify?
Sean,
It's about order of operations. The first fragment should be evaluated from the inside out, NOT the outside in. s should not be modified until the entire block has been evaluated. The third block looks strange because that is how CF8 decides to implement it. Just paste the first block into a test page on CF8 and think to yourself, why does this error?
Think of a duck typed use case, like barney's example. s could be called, animals for example. He has a simple list representation as a starting point, but decides to transform it into a complex structure and… oh lets say he's in a cfc function body. Why go to all the trouble to var yet another variable to represent the same data in a different form, we arn't going to need the list afterward… GONK.
Sean,
Joshua nailed it.
The third example is insane – it doesn't make any sense at all – and that's my point. As near as I can tell, that represents how ColdFusion evaluates the first snippet, instead of doing it like the second snippet (which is correct).
OK, that was completely unclear (to me). I didn't realize you were saying the first fragment didn't work! Yeah, then in that case, I agree that it's broken.
I absolutely hate the "=" syntax, what were they thinking!? I imagine the thought process was "easier for developers to 'get'", but I still think its absolutely unconventional.
I wasn't aware you couldn't nest structs using literal syntax either, interesting.
Derik,
With CF 8.0.1, you can mix-and-match nested array and struct literals (e.g. [{id=1}, {id=2}]). It was only disallowed in the initial 8.0 release.
Even more perplexing for the '=' decision is that both JavaScript, and named CFC/UDF parameters use the ':'. The '=' is accepted for named CFC/UDF parameters, but not required. To make it consistent with the existing language features, they should have at least allowed both. I'd have preferred to only allow ':' and deprecate the '=' in CFC/UDF parameters, but oh well.
Sigh, this does seem to be an extremely half baked feature. Hopefully once the CFML committee is up and running and there's a real standard for how the language should behave we'll be able to push Adobe to fix this stuff.
I'd really like to see allowing quoted strings in the name part.
{ "Something With Spaces" = [ "a", "b", "c" ] }
php, ruby, python, perl, groovy, javascript, as3 … Everyone has literal notation like this now that allows quotes and proper nesting.
Why are we in the stone age? :/
Also, for that matter, why can't we pass literals as attribute values or directly in function calls?All the above languages also support that.
Elliot,
Having quoted keys would definitely be a nice feature. Though even better would be allowing colons or equals signs for the key/value separator so you can use a colon like basically every other language.
On Railo, you can use struct/array literals as expressions, meaning you can use them in CFRETURN, as function/method arguments, or any where else. The only-assignment restriction is a ColdFusion issue, not a CFML issue. So people are implementing it correctly, just Adobe totally dropped the ball.
[...] Ben Nadel posted another interesting code snippet this moring. NEVER EVER USE IT. It leverages a horrible bug in ColdFusion's implementation of struct literals that I've blogged about previously. [...]
[...] lets you write some really nasty code, causes some weird bugs, and today I realized (through some handy errors on our production cluster) that there are thread [...]
Barney, have you submitted this as a bug now that we have the public bugbase? I'd vote for it, and I know a handful of others that would, too.
Adam,
I haven't. And it's not in the bug base either. But jesus is that a horrible example of how to build a Flex app. I give up.
I have submitted it via the feedback/bug report form, but no idea where things go after that.