Using “continue” To Short-Circuit .each() Iteration In ColdFusion

Cyberdime
Published: January 18, 2023

CAUTION: This is likely a bug in the CFML language; but, it’s kind of neat in that it expresses loop iteration intent slightly differently.

Yesterday, I was refactoring some ColdFusion code to go from using a standard for-in loop to using an .each() iteration member method. The for-in version of the code had some short-circuiting logic that used continue statements to skip to the next loop iteration. And, when I refactored to using .each(), I forgot to change the continue keyword to be a return keyword. And, wouldn’t you know it – the code worked anyway. This is likely a quirk, not a feature, of the CFML platform; but, I thought it would be fun to share.

To see this in action, I’m going to perform a nested loop. The outer loop will use the for-in syntax to iterate over words. The inner loop will use the .each() syntax to iterate over the letters in each word. And, when iterating over the letters, I’m going to use the continue statement to skip over any vowels:

<cfscript>
	words = [ "Bloody", "Hell", "Man" ];
	// OUTER LOOP: Using a standard for-loop here, which would normally work in
	// conjunction with the "CONTINUE" statement.
	for ( word in words ) {
		writeDump([ "START: #word#" ]);
		// INNER LOOP: Using an iterator, which would normally work in conjunction with
		// the "RETURN" statement.
		word.reMatch( "." ).each(
			( letter ) => {
				// Skip outputting any vowels.
				if ( letter.reFind( "[aeiou]" ) ) {
					// CAUTION: This should have been a RETURN statement; but, I
					// accidentally left in CONTINUE when I was refactoring my code. But,
					// it seems to work fine in both Lucee CFML and Adobe ColdFusion.
					continue;
				}
				writeDump([ letter ]);
			}
		);
		writeDump([ "END: #word#" ]);
	}
</cfscript>

Notice that at the end of the outer-loop, I’m outputting a value. This is important because it will help us determine if the continue statement within the inner loop is accidentally short-circuiting the outer loop, not the inner loop. And, when we run this code in both the latest Lucee CFML and Adobe ColdFusion, we get the following output:

Page showing that every non-vowel letter in each word has been successfully output.

As you can see, we output every non-vowel letter in both CFML runtimes. This output has some critical point:

  1. No error was thrown – the code ran successfully.

  2. No vowel was rendered – the continue statement successfully exited the inner .each() loop.

  3. The "END:" markers were output for every word, indicating that the for-in loop ran fully even though there was a nested continue statement.

While I know that this likely runs by accident, there’s something I like about it. Using continue expresses more intent when compared to using return. I understand that there is nothing technically different about the .each() method – it’s just a member method; however, using continue does make it feel more loop-like.

Anyway, happy hump day!

Want to use code from this post?
Check out the license.

Source: www.bennadel.com