Simpler and (ever so) slightly faster looping in Lucee cfscript
The ability to loop a given number of times is a basic programming concept and for the last two decades, writing first javascript and then CFML script, I've largely been using the familiar "C-style" syntax.
for( i=1; i <= 10; i++ ){
currentValue=i;
}
Not intuitive
Despite regularly using the construct, I admit it was quite a while before I grasped what all the algebra-like stuff inside the parentheses actually did. Logical of course, but not particularly intuitive.
As CFML has evolved and especially since we moved over to Lucee from ColdFusion 9, I find I rarely need this particular type of for-loop any more. In most cases I'm iterating over an array, query or struct rather than needing to loop a certain number of times and the language now allows you to do this without needing to handle the increments: using "for-in" loops or the (relatively) new iteration functions.
Still, I do have a few of those C-style for-loops dotted around my code base where I just want to iterate a set number of times.
Tag in script
From now on though, I plan to ditch them in favour of the following:
loop from=1 to=10 index="i"{
currentValue=i;
}
Some dislike the whole "tags-in-script" implementation, but not only is this to my eyes clearer and more expressive than all those semi-colons, angle brackets and plus signs, according to Gert it's also a little bit faster in the current version of Lucee (4.5.2.018).
Putting this to the test:
struct function loopTest( method, iterations ){
var milliseconds=0;
stopwatch variable="milliseconds"{
switch( method ){
case "for":
for( var i=1; i <= iterations; i++ ){
// do something
}
break;
case "loopFromTo":
loop from=1 to=iterations index="local.i"{
// do something
}
break;
}
}
var result={};
result[ method ]=milliseconds & "ms";
return result;
}
iterations=100000;//one hundred thousand
Dump( loopTest( "for",iterations ) );
Dump( loopTest( "loopFromTo",iterations ) );
(Side note: I've used local.i
to scope the index variable in the "loopFromTo" version even though I normally prefer using the var
keyword to declare local vars. In this case I think it reads better and subsequent references to i
don't need to be scoped).
Executing the above code a dozen times to eliminate compilation delays, the sort of results I'm seeing on my fairly beefy dev machine are:
for | 15ms |
---|---|
loopFromTo | 0ms |
That is not significant. Even with a million loops I'm only seeing an approximate difference of 100-150ms.
But I'll take it along with the far more important clarity it offers.
Times-are-a-changing
As Gert notes, Lucee 5 will add a new option for simple "times" looping where no index reference is needed. I haven't tested it yet but it promises to be fast—and very clear.
loop times=100000{
// do something (and make it snappy)
}
Comments