Odd CFLoop Condition Runtime Compilation Bug

Posted December 11, 2009 at 4:12 PM by Ben Nadel

Tags: ColdFusion

Yesterday (or was it the day before), Mark Mandel brought up a very odd CFLoop / Condition runtime compilation error on Twitter. It involved evaluating explicit True / False data types in order to prepare the Condition attribute of the CFLoop tag. To demonstrate this, take a look at the following code snippets and their associated output:

  • <!--- Store true in a variable. --->
  • <cfset isTrue = true />
  • <!--- Demonstrate that TRUE can be used in hashes and parens. --->
  • Is True: #(true)# | #true#<br />

Is True: true | true

  • <!--- Loop while true. --->
  • <cfloop condition="isTrue">
  • Loop True (delayed variable evaluation).<br />
  • <cfbreak />
  • </cfloop>

Loop True (delayed variable evaluation).

  • <!--- Loop while true (with hash). --->
  • <cfloop condition="#isTrue#">
  • Loop True (immediate variable evaluation).<br />
  • <cfbreak />
  • </cfloop>

Loop True (immediate variable evaluation).

  • <!--- Loop while true (without variable). --->
  • <cfloop condition="#true#">
  • Loop true (immediate evaluation).<br />
  • <cfbreak />
  • </cfloop>

Invalid CFML construct found on line 1 at column 2. ColdFusion was looking at the following text: true The CFML compiler was processing: An expression beginning with #.

  • <!--- Loop while true as string. --->
  • <cfloop condition="#toString( true )#">
  • Loop true (immediate evaluation as string).<br />
  • <cfbreak />
  • </cfloop>

Loop true (immediate evaluation as string).

  • <!--- Loop while true as string (delayed evaluation). --->
  • <cfloop condition="toString( true )">
  • Loop true (delayed evaluation as string).<br />
  • <cfbreak />
  • </cfloop>

Loop true (delayed evaluation as string).

This is too odd. It's like the immediate evaluation of the data type True (False is the same) simply doesn't translate into a string value that can be used in the delayed-evaluation of the Condition attribute. However, you'll notice that if we run the True data type through the ToString() method first, even with immediate evaluation, it works fine. This has got to be a bug?? Can anyone offer any insight that I'm not thinking about?




Reader Comments

Dec 12, 2009 at 3:49 AM // reply »
7 Comments

does look like a bug...
especially considering delayed evaluation works fine
<cfloop condition="true">


Dec 12, 2009 at 7:31 AM // reply »
12 Comments

This reminds me of a problem I encountered yesterday (and solved with your help). If you create an xml with cfxml, you cant create a cffile on MX7 (CF9 can), except you parse it toString. I know, not really the same, but this may be a bug that some variables are not parsed automatically.

Did you do this on CF9?


Dec 14, 2009 at 8:24 AM // reply »
10,640 Comments

@Roman,

I actually ran this on CF8. I still do most of my R&D on CF8 since we have no CF9 production box yet.


Dec 14, 2009 at 8:37 AM // reply »
12 Comments

Okay, if I find some time this evening, I'll run this script on CF9.. just in case. And to satisfy my curiosity ;-)


Dec 14, 2009 at 8:39 AM // reply »
10,640 Comments

@Roman,

Awesome - sounds like a plan.


Dec 14, 2009 at 3:56 PM // reply »
12 Comments

Ah okay, I tried some things out and I got the same result on CF9. So it doesn't have anything with my problem I had.

After experimenting some time I can't add anything to your discovered problem. This is strange and could be called a bug. I tried about 10 ways to set true as a variable (like <cfset true = 1 /> and so on (yea I know, I'm crazy and it is senseless to try this... but I wanted to :-P)) but this is impossible. So, yea, why doesn't Coldfusion automatically parse the 'true' string?


Dec 14, 2009 at 10:29 PM // reply »
43 Comments

This reminds me of a problem I ran into in CF8 where I used the Java method indexOf() to do array searching in CFML.

arr.indexOf("findMe")

Passing in simple values as seen above would work fine, but when I passed in a field from a query variable, it would always fail.

arr.indexOf(qry.col1) - always returns -1

I had to escape anything within parenthesis using toString() like you did here.

arry.indexOf( toString(qry.col1) )

I think deep down it has something to do with typing. Just when you thought toString() was useless, huh?


Dec 15, 2009 at 6:35 PM // reply »
10,640 Comments

@Roman,

Yeah, the fact that this works:

<cfset x = true />
<cfloop condition="#x#">

... and this fails:

<cfloop condition="#true#">

... seems funky, right? It's just a simple substitution. Unless, the CFSet is actually not copying the actual data type "true", but is, instead converting it to a string value?? Perhaps I'll try CFDumping out the underlying class to see what's going on.

@Jose,

Talking between ColdFusion and Java can definitely hiccup when it comes to data types. I think technically, the query.col reference actually returns the underlying Java record set column object... I know that query[ "col" ] returns an object that can take array functions:

http://www.bennadel.com/blog/167-Calling-Array-Functions-on-ColdFusion-Query-Columns.htm


Dec 18, 2009 at 1:28 PM // reply »
2 Comments

@Ben,

Hi Ben,

First thanks for all your posts. They bring light and clarity to a lot of CF topics.

About this issue, I don't think it's a bug. CF is funky that way. It's just a matter of type and evaluation order which in CF is translated to how we use '', ## or both.
In this case the condition accepts a string or an expression and that's why these will work:

<cfset x = true />

<cfloop condition="x">
<cfloop condition="#x#">
<cfloop condition="'#x#'">

or

<cfloop condition="true">
<cfloop condition="'#true#'">

The fact that <cfloop condition="#true#"> this doesn't work means that we are dobleevaluating the expression and it also means what you said that CF will accept the result of #x# as a string.

This is much like the Evaluate() function. If you run these scenarios with the Evaluate() function it kind of starts to make sense.

The whole topic of the evaluation order and the use of "" and ## is probably the most confusing in CF. There is no clear cut when where and how you use or combine them. Many times the whole process is a black box.
For example since we are talking about cfloop:

<cfset x = StructNew()>

This will work:

<cfloop collection="#x#" item="item">

</cfloop>

and this will not:

<cfloop collection="x" item="item">

</cfloop>

however this will work in a condition loop:

<cfloop condition="x"> (x being an expression/variable that evaluates to true or false or a number or a 'true' 'false' string)

I guess that's the price we have to pay for CF being typeless.


Dec 18, 2009 at 4:17 PM // reply »
10,640 Comments

@Geno,

If you run this code:

<cfset t = true />
<cfdump var="#getMetaData( true ).getName()#" />
<cfdump var="#getMetaData( t ).getName()#" />

... you get the following output:

java.lang.String
java.lang.String

As you can see, both the data type, "true", and the copy of, "true" - t - are being stored as a string value. They are the same data type. As such, I don't think it should follow that:

<cfloop condition="#t#">

... works and:

<cfloop condition="#true#">

... does not.

Maybe there is just something I am not wrapping my head around properly.


Dec 18, 2009 at 4:58 PM // reply »
2 Comments

@Ben,

Good test but the getMetaData( t ).getName() can't be trusted.

If you ran this code:

<cfset t = 1 />
<cfparam name="x" type="boolean" default="true">

<cfdump var="#getMetaData( t ).getName()#" />
<cfdump var="#getMetaData( x ).getName()#" />

You get:

java.lang.String
java.lang.String

Even if you substitute t for 1 as in:

<cfdump var="#getMetaData( 1 ).getName()#" />

You still get:

java.lang.String

However, and this makes this whole thing more interesting, when you ran this:

<cfdump var="#getMetaData( IsBoolean(x) ).getName()#" />

You get:

java.lang.Boolean

If you output the value of the function as:
<cfoutput>#IsBoolean(x)#</cfoutput>

CF returns 'YES'.

Anyway I hope this will be helpful in some way.


Dec 18, 2009 at 5:00 PM // reply »
10,640 Comments

@Geno,

Hmmm. I'm not sure what to even make out of this :) It's like ColdFusion keeps trying to convert all simple data values to String when possible.

I have no answers at this point :)


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 12, 2012 at 3:37 AM
Learning ColdFusion 8: CFImage Part III - Watermarks And Transparency
Hi Ben, Just to ask currently it is placed bottom right corner, if i need to replace the same rendered image on the bottom left side or in the bottom center, how that can be calculated. bottom ce ... read »
Feb 11, 2012 at 9:29 PM
Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping
I can't say how glad I am that I found your post. Thank you very much. ... read »
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »