Learning ColdFusion 8: All Hail The New ++ Operator
ColdFusion 8 has introduced some new, very exciting mathematical operators. Most of these operators can be used through out the ColdFusion language while some (since ColdFusion is a tag-based language) can only be used and parsed properly from within a CFScript block. The following operators can be used any where: ++, --, %, +=, -=, *=, /=, %=, &&, ||, and !. The following operators can only be used within CFScript: ==, !=, <. <=, >, >=. And, &= can be used anywhere to concatenate a string to "self".
All of those operators are good, don't get me wrong, but I have been waiting so long for the ++ operator to get here. This operator increments a given value. Placing this operator before or after a variable has different effects. Placing it after the variable causes the variable to be evaluated first and then incremented. Placing it before the variable causes the variable to be incremented first and then evaluated.
<!--- Set the intial value. --->
<cfset intKisses = 0 />
<!--- Increment after variable evaluation. --->
A. #intKisses++#<br />
<!--- Increment before variable evaluation. --->
B. #++intKisses#<br />
This gives us the following output:
A. 0
B. 2
Notice that on line A, the value, intKisses, was evaluated and displayed prior to the increment. Then, on line B, it was incremented first and then evaluated and displayed. One of the first things that jumps to mind with this operator is how much nicer the last property of a FOR-Loop will look in CFScript:
<cfscript>
for (intI = 0 ; intI < 5 ; intI++){
WriteOutput(
IIF( intI, DE( "," ), DE( "" ) ) &
intI
);
}
</cfscript>
This gives us the following output:
0,1,2,3,4
Notice how much nicer it was to use intI++ rather than the unsightly intI = (intI + 1). Does anyone else feel like shedding a tear or two over this simplistic beauty?
These operators can also be used inside of delated evaluation expressions, such as those used in conjunction with ColdFusion's IIF() method:
<!--- Set initial value. --->
<cfset intKisses = 10 />
<!---
If the number of kisses received is less
than 10, increment the value. If it is greater
than or equal to 10, decrement the value.
--->
#IIF(
(intKisses LT 10),
"++intKisses",
"--intKisses"
)#
<!---
Output the kiss count to make sure that the
variable was indeed updated.
--->
#intKisses#
This gives us the output:
9
9
Notice that the operator acted on the variable, intKisses, only when the codition held true (and in a delayed manner). Also notice that not only was the value incremented for use in the display, the second outputted number proves that the value continues to be incremeted even after the delayed evaluation.
Another form of delayed evaluation is that of the tag-based ColdFusion condition method. Remember, the condition attribute of a condition loop is evaluated for each iteration of the loop to determine whether or not another iteration can take place. This is a place where these operators can be applied:
<!---
Set our goal - the number of hugs
we hope to get.
--->
<cfset intGoalHugs = 10 />
<!---
Set the number of hugs that we are going
to start with.
--->
<cfset intHugs = 0 />
<!---
Keep looping until our hug count is at least
as great as our goal hug count.
--->
<cfloop condition="(intHugs LT intGoalHugs++)">
<!--- For each iteration, add TWO hug. --->
<cfset intHugs++ />
<cfset intHugs++ />
#intHugs# of #intGoalHugs#<br />
</cfloop>
This gives us the output:
2 of 11
4 of 12
6 of 13
8 of 14
10 of 15
12 of 16
14 of 17
16 of 18
18 of 19
20 of 20
Not only was the variable, intHug, incremented explicitly in the body of the loop, the variable, intGoalHugs, was also evaluated for each iteration and at the time of that evaluation, the variable was incremted.
This operator also works in the Evaluate() method, but come on, does anyone still use that function??
The ++ operator will dynamically convert booleans into numeric values prior to evaluation:
<!--- Set boolean. --->
<cfset blnTrue = true />
<!--- Pre-increment the boolean value. --->
#++blnTrue#
This gives us the output:
2
In this case, since we are applying a mathematical operator, ColdFusion converts the boolean value of TRUE into a one. It then pre-increments the 1 and returns 2.
Similarly, using the ++ operator with date/time objects will dynamically convert dates into their numerical floating values and perform "date math" on them:
<!--- Get today's date. --->
<cfset intToday = Now() />
<!--- Output tomorrow's date. --->
#DateFormat( ++intToday )#
This gives us the output (this was run on May 31st):
01-Jun-07
One note of caution when using this operator to convert data types: since this operator acts directly on the variable, the ongoing data type of that variable is changed. So, for example, with out date math example, if, after we performed the date math, we output the intToday variable:
#intToday#
... we get the value:
39234.8717708
intToday no longer holds a date in string format.
There are, however, some limitations to the way these operators can be used. For starters, while they can be used as part of mathematical equations if the value being incremented is a variable:
<!--- Set initial kiss count. --->
<cfset intKisses = 0 />
<!--- Alter kisses and then some. --->
#(++intKisses + 2)#
... which gives us:
3
... if you tried to do that with a straight-up number:
#(++0 + 2)#
ColdFusion will throw the following error:
Invalid CFML construct found on line 44 at column 3. ColdFusion was looking at the following text: ++
Now, why would you want to do that with a number, not a variable, no idea. You wouldn't, but at least now you know that it cannot be done.
These operators must not be used in conjuction with a nameless function return value. Imagine a scenario where we wanted to get the next available index of an array, we might do something like this:
<!--- Define an implicit array. --->
<cfset arrValues = [ 1, 2, 3 ] />
<!--- Get the next index we would use for the array. --->
<cfset intNextIndex = ArrayLen( arrValues )++ />
Sounds good, but unfortunately, ColdFusion throws the same invalid CFML construct error. This is something that I could have seen being quite useful at times. It's a shame that ColdFusion doesn't handle returned values more elegantly in general (not just with operator use but with many commands really).
This operator cannot be used in conjunction with the access of an underlying Java method. Trying to pre-increment a number and then get its string value:
<!--- Set initial value. --->
<cfset intKisses = 0 />
<!--- Pre-increment and get string value. --->
#++intKisses.ToString()#
... throws the ColdFusion error:
Invalid CFML construct found on line 53 at column 22. ColdFusion was looking at the following text: (
Again, this is something that you probably will not do, but this is an exploration of the new ColdFusion 8 features. I am just trying to get a thurough sense of can and cannot be done.
While this is an in-depth exploration of ColdFusion 8's new ++ operator, I am sure most of the other new operators will have the same exactly or very similar limitations.
Want to use code from this post? Check out the license.
Reader Comments
Nice overview, and yes I have been waiting for this for loops for ever since I started using CF :)
Ben,
these operators work on a variable. With these operators, only a variable's value can be incremented or decremented. For example, when x=1, x++ will increment the value of x to 2 and x-- will decrement the value to 0.
You can not expect these operators to work on constants. i mean do you expect 1 to change to 2 if you do 1++ :)
Same thing applies to method return values. if you assign the returned value to a variable and apply these operators on that, it would work. it can not work on the returned value itself because it is a constant.
This is what happens in all the programming languages.
I don't see any kind of limitations here.
btw, nice overview.. and you've covered it really well..
Rupesh.
Does this #(++intKisses).ToString()# work?
@Rupesh,
To be honest, I have never attempted to put this operator on a constant in any other language, so I have no idea if it would work. I agree that this is not a limitation... it was merely me trying to figure out all the ways it wouldn't work.
As for things being applied to function returns, I see what you are saying about the value being a constant; however, it merely reminded me that ColdFusion, in general, does a poor job of handling method return values. Take my Echo() method, which just returns back what ever was passed to it. Using it in this manor:
<cfset objData = [ "A", "B", "C" ] />
#Echo( objData )[ 2 ]#
Throws a ColdFusion error. But it really should not. Echo() returns the array and then I am grabbing the value at the second index of the returned value. Similarly, if the returned value is a function, I cannot invoke it directly:
#Echo( Echo )( "Echo Test" )#
Throws a ColdFusion error. But, it really should not. Echo() is returning the pointer to itself and then I am asking to echo back the phrase.
The issue with these is not one of functionality, but rather of parsing. I would love to see these parsing issue resolved over the next few iterations of ColdFusion (I love this language and I am more than happy to wait for them).
Just so I am not going crazy, I tested these both in Javascript and they work as expected (I don't want to pull for something that other languages deem crazy).
That being said, I understand that applying the operator to a constant makes no sense :) I didn't think of the values as constants - I am used to thinking in terms of variables.
@Chris,
No, that does not work. In general in ColdFusion, placing () around a value does not change any parsing issues.
Good stuff, but I'm still holding my most raucous applause for ternary operators when/if they get introduced. :-)
@Rob,
What is the ternary operator? Is that what this is:
(condition) ? true : false ;
I use that in Javascript all the time and would love to see it in ColdFusion.
That's the one. It's a crowd pleaser in JS and I've been doing a lot of <gasp!> PHP lately which allows me to get my fix. :-)
Doesn't the IIF function something similar?
@Chris,
Yes, IIF() acts very much like the ternary operator.
But a bit of a clumsy implementation of it, IMO...
Exactly, especially because of the whole delayed evaluation. There are ways to get around the ternary operator, but if it was there, it would definitely get used.
I have found plenty of times that the IIF() function does not even work correctly :(
Where in something like Javascript or Actionscript the ternary operators allow any valid expression to be evaluated, in Coldfusion quite often this will fail and I have had to revert to the if statement to achieve the same thing.
Okay here is one of those trademark ColdFusion "features" for you...
Run this:
<cfscript>
"last" &= "first";
writeoutput( last );
</cfscript>
But you have to first guess what you think that will output....
@Brett,
This looks crazy! I am gonna guess that it comes out to be:
first
Here's my reasoning (before I test). ColdFusion can allow you create dynamic variable names using double quotes. So, the parse is going to think you want to create a variable dynamically named "last", which is empty??? Then you are going to append "first" so the value of Last. Either that or it throws an error?
Ok time to test....
And it actually comes out to be:
lastfirst
I guess, this makes sense. It first concatenates the two string values, last and first and then stores them into the dynamic variable "last". Still, very strange :) Thanks for pointing out this little tidbit.
Yeah it is strange to say the least :) I'm not actually sure if it is intended - if it will be supported moving forward. Bonus points if we can come up with a scenario where this might be useful.
cheers.
> The following operators can be used any where: ++, --, %, +=, -+, *=,
> /=, %=, &&, ||, and !.
I think that fifth one (-+) should be -=.
@Chris,
Nice catch. You are correct.
I'm really behind the times, company is still running on CF7... but we're about to upgrade and now knowing this I'm going to push for a faster upgrade!
This is the best (not so new anymore) news ever!
I should really do more to keep up.
@Pete,
What are you upgrading to? 8? ColdFusion 9 will be released shortly (we think).