2

I have been having the hardest time trying to resolve the weirdest error when any kind of condition is used within any kind of loop.

The error I keep getting is: "Complex object types cannot be converted to simple values." on the line that contains <cfloop condition="true">. What's even funnier is that a <cfbreak> doesn't break out of the loop. I have used the debugger within Eclipse to confirm that this code is actually executed.

The odd thing is sometimes the code loops forever even though I know the <cfbreak> gets executed and sometimes it errors out on the first iteration.

I've confirmed that this issue occurs on two other computers as well.

Before everyone freaks out on my use of the always true condition, I used to have a valid condition: <cfloop condition="not done"> where done was a boolean. This caused the same error.

I'm working on older code written by someone else, so rewriting isn't an option at this time.

I have just patched ColdFusion 8.0.1 to the latest updater 4 to see if that would resolve the issue and it hasn't.

This is what the code essentially looks like:

<cfloop condition="true">
    <cfif condition is true>
        <cfbreak>
    </cfif>
</cfloop>

Here is the code that does get executed:

<cfset done = false />
<cfloop condition="true">
    <cfscript>
        try
        {
            lineitem.quantity = quantityRemaining;

            quantityRemaining = 0;

            arrayAppend( currentTub, lineitem );

            currentCartItemCount = currentCartItemCount + lineitem.quantity;
            currentTubItemCount = currentTubItemCount + lineitem.quantity;

        }
        catch(Any e){}


        availableSpaceInCart = this.itemsPerCart - currentCartItemCount;
        availableSpaceInTub = this.itemsPerTub - currentTubItemCount;
    </cfscript>

    <cfif quantityRemaining LTE 0>
        <cfset done = true />
        <cfbreak />
    </cfif>
</cfloop>

UPDATE:

Well we figured out what the issue was. There was two <CFOUTPUT> tags wrapped around this loop, the outer <CFOUTPUT query='query_name' groupby='column_name'> tag was using a QueryNew() generated query which for some reason ColdFusion didn't like. So we resolved that issue and it resolved our weird issue.

James A Mohler
  • 11,060
  • 15
  • 46
  • 72
Salsero69
  • 2,160
  • 3
  • 23
  • 27
  • could u post the actual cfloop code? – Henry Oct 12 '11 at 18:53
  • What do you get if you do `condition="#True#"`? – Dan Short Oct 12 '11 at 18:54
  • @Henry Not really, it's client code, but within the is just some variable additions and concatenations. Although I did comment out two lines which were totally unrelated and the loop seemed to behave. – Salsero69 Oct 12 '11 at 18:58
  • @DanShort I get an error when I try that. ColdFusion was looking at the following text: true The CFML compiler was processing: An expression beginning with #, on line 1, column 1.This message is usually caused by a problem in the expressions structure. – Salsero69 Oct 12 '11 at 19:00
  • Just an idea, can u install CF9 dev edition and try the same code and see what happen? – Henry Oct 12 '11 at 19:04
  • @Henry Yes and no. We're working on client code that is already set-up and running on CF8. So to install the app in CF9 would be a waste of time as it would require them to reinstall everything. – Salsero69 Oct 12 '11 at 19:08
  • If Time == Money, and Upgrade to CF9 fixes it, maybe it's a solution. :) – Henry Oct 12 '11 at 19:20
  • @Henry Agreed, in a perfect world. – Salsero69 Oct 12 '11 at 19:26
  • That makes no sense at all. \*shrug\* You should put the details of how you solved the problem as an answer and mark it resolved. – Peter Boughton Oct 13 '11 at 15:26
  • @PeterBoughton Will do. And no it doesn't make any sense. I've run into quite a few issues in CF that make no sense. – Salsero69 Oct 13 '11 at 18:43

4 Answers4

2

You are passing ambiguous values to a conditional loop.

When you write:

<cfloop condition="x">

You are telling ColdFusion: continue to loop so long as 'x' evaluates to true. This could be a statement like (myvar gte 10), which would evaluate to true if myvar is greater than or equal to 10. If some mechanism inside the loop decrements myvar, eventually, a pass through the loop will cause it to stop, because myvar will no longer be greater than or equal to 10 (it has dropped below 10).

Now, let's look at your condition:

<cfloop condition="true">

Is CF considering it as:

<cfif 'true'>

Or

<cfif TRUE>

One is definitely wrong, and will throw an error, if you write into a ColdFusion statement. You will probably find that you cannot evaluate a "string" into a boolean TRUE or FALSE evaluation. I'm almost certain the parsing of a string value is confusing ColdFusion with the actual boolean TRUE or FALSE value. It is perhaps this lexical conversion of 'true' to TRUE that is causing your object-related errors. What you want, more than likely is:

since the value of done is set to FALSE to start, which, when coupled with a logical NOT, evaluates to true.

Then, later down your statement:

   <cfif quantityRemaining LTE 0>
        <cfset done = true />
   </cfif>

There is no need for a <cfbreak> statement, which forcibly breaks you out of a loop. If you are conditionally looping, the evaluation of that variable will affect the iteration of the loop (read: it will stop it).

Furthermore, you may very well want to change your condition to:

<cfloop condition="quantity LTE 0">

and will not require the done variable at all.

Shawn Holmes
  • 3,752
  • 22
  • 25
  • _"You will probably find that you cannot evaluate a "string" into a boolean TRUE or FALSE evaluation."_ -- HUH!? CF is dynamically typed - it can and will convert strings to boolean. Both `` and `` will work fine. You can even write `` and the strings will be concatenated then converted to boolean. – Peter Boughton Oct 13 '11 at 13:06
  • Condition should be changed to if the done is removed. If LTE then you'll get an infinite loop. – Barry Jordan Oct 13 '11 at 13:13
  • The opposite of `LTE 0` is `GT 0`, not `GTE 0`. – Peter Boughton Oct 13 '11 at 13:54
  • @Peter It appears that 'true' does evaluate to TRUE, after all. However, as is the case with a lot of CF code...just because you *can* do this, doesn't mean should. To clarify your statement, it will dynamically convert the string 'true' to boolean...not all strings; "apple" is not converted into a boolean. – Shawn Holmes Oct 13 '11 at 16:57
  • CFML is a dynamically typed language. If it needs a boolean and has a string, it will convert that string a boolean, if it can. Likewise if it has a string and needs a number, it will attempt a conversion. That's how dynamically typed languages work. It's a good thing and allows us humans to write less complex code. Saying you shouldn't use the dynamic conversion features of CFML just because the word apple can't be automatically translated to a boolean is silly. – Peter Boughton Oct 13 '11 at 17:20
  • Sadly, StackOverflow is meant to be more about fact, and less about opinion (which is a shame)--since this would be a good opportunity to breed best practices. Can you freely exchange types in CF? Yes. Should it be done? No--it's not going to prepare for other language development where things are strongly typed--and it is going to make troubleshooting situations like this difficult. Focusing in on my apple example and not on the fact that mixing types is a bad practice in real world programming is short-sighted. – Shawn Holmes Oct 13 '11 at 20:14
  • Mixing types is NOT bad practise. Writing `` is unnecessarily verbose, which is why people just do ``. If you want opinions/discussion, post it on [cf-talk](http://www.houseoffusion.com/groups/cf-talk/) and we can see what others think, but I already know I'm right. ;oP – Peter Boughton Oct 13 '11 at 22:37
  • I think you are mixing up the questions now, because you just quoted back to me my answer for a different question as a proof of why this unrelated question is wrong...and now I am confused. – Shawn Holmes Oct 14 '11 at 00:09
1

It seems from your code that you want to break out of the loop if the value of quantityRemaining reaches 0 or lower. So why not use that as the condition in the cfloop, rather than using 'true'. Then you can remove the cfbreak block since that's essentially what the cfloop condition is doing.

<cfset quantityRemaining = 5>
<cfloop condition="quantityRemaining GT 0">
    <!--- your code here --->
    <cfoutput>#quantityRemaining#<br></cfoutput>

    <!--- don't forget to change the value, otherwise you'll loop forever --->
    <cfset quantityRemaining = quantityRemaining - 1>
</cfloop>
Nick Harvey
  • 96
  • 1
  • 3
  • I had tried a bunch of conditions and just as I had suspected the issue is wholy unrelated to the error being reported. Well the error may be correct, but the line of code causing the error was grossly wrong. See my update above. – Salsero69 Oct 13 '11 at 18:43
1

The error "Complex object types cannot be converted to simple values." means exactly that.

Complex objects - objects,arrays,structs,queries,etc - cannot be converted to simple values - strings,numbers,dates,booleans,etc - because there's no globally defined way of doing that.

Based on the code you've posted, at least one of these variables does not hold a simple value:

  • currentCartItemCount
  • currentTubItemCount
  • lineitem.quantity
  • this.itemsPerCart
  • this.itemsPerTub
  • quantityRemaining

To find out which one, put this before the loop:

<cfdump var=#isSimpleValue(currentCartItemCount)# />
<cfdump var=#isSimpleValue(currentTubItemCount)# />
<cfdump var=#isSimpleValue(lineitem.quantity)# />
<cfdump var=#isSimpleValue(this.itemsPerCart)# />
<cfdump var=#isSimpleValue(this.itemsPerTub)# />
<cfdump var=#isSimpleValue(quantityRemaining)# />
<cfabort/>

If any output false (or no) then unwrap the isSimpleValue function to find out what it contains and trace the code backwards to find out why.

If you get the true (or yes) six times, then something else is going on, and you probably need to share more code.

Peter Boughton
  • 110,170
  • 32
  • 120
  • 176
  • We tried all that and none of those variables were an issue. See my update above. – Salsero69 Oct 13 '11 at 18:40
  • Yeah, I was taking the error message at face value, when obviously something else was going on behind the scenes. _It's always handy when CF does that._ :/ – Peter Boughton Oct 13 '11 at 22:31
0
<cfloop condition="true">

is the same as

<cfloop condition=true>

just as <cfif 'true'> is the same as <cfif true>

What you are basically setting up there is an infinite loop, as your condition will always be true. If your code never breaks out of this you're going to be in serious trouble.

What you probably want to do is the following, and remove the <cfbreak> from your loop.

<cfloop condition="quantityRemaining GT 0">
Barry Jordan
  • 2,666
  • 2
  • 22
  • 24