tracker issue : CF-4204017

select a category, or use search below
(searches all categories and all time range)

CFLOOP ignores undefined array elements when looping over an array

| View in Tracker

Status/Resolution/Reason: Closed/Fixed/Fixed

Reporter/Name(from Bugbase): Graham B. / ()

Created: 02/11/2019

Components: Tags

Versions: 2016,2018

Failure Type: Data Loss

Found In Build/Fixed In Build: ColdFusion: 2016,0,07,311392-Evaluation / 314559

Priority/Frequency: Normal / All users will encounter

Locale/System: ALL / Platforms All

Vote Count: 1

Problem Description:
CFLOOP, when iterating over an array, will *skip* array values that are undefined (such as when a query returns a null value, or when a left join has no joined value, among others).

Steps to Reproduce:
Create an array with one or more *undefined array elements*. Loop through the array using `<CFLOOP array="">`.

Actual Result:
Unbelievably, CFLOOP just jumps right past the undefined array elements. For example, an array of length 8 will not execute 8 times.

Expected Result:
CFLOOP will execute the same number of times as the length of the array. Undefined array elements will be supplied to the index so that a query returning multiple results doesn't have arrays of different lengths for different rows.

Any Workarounds:
Use other means to loop, but seriously why even have CFLOOP support arrays if it's unusably broken.



See my comment for more detail.
Vote by Charlie A.
30320 | February 18, 2019 03:31:41 PM GMT
That's a helpful observation, Graham. Thanks for filing it. I have a workaround you may want to consider (the arrayisdefined function in a more traditional loop over the array), as well as some more for Adobe and readers to consider. First, I'll note that support for empty LIST elements was indeed added in CF8, for certain functions like listtoarray, listlen, and several others, adding a new includeemptyelement arg as a boolean. That would allow the empty list elements to still be "handled". Sadly, such handling of undefined/empty array elements was never added to array functions, nor was it added to cfloop when using the ARRAY or LIST attributes. But one thing that WAS added in CF8 which could perhaps help you was a new arrayisdefined function, which tests if a given element in an array isundefined. And while that won't help within your current code doing a cfloop over the array using the ARRAY attribute, it would work for you if you could change to the more traditional CFLOOP with from/to/index attributes. That WOULD loop over all array elements, and then you could decide in code how to handle the empty element with that arrayisdefined function. Here's a simplified example: <cfset myArray = arrayNew(1)> <cfset myArray[1] = "val1"> <cfset myArray[3] = "val2"> <cfloop from=1 to="#arraylen(myArray)#" index="i"> Value: <cfif arrayisdefined(myArray,i)> <cfoutput>#myArray[i]#</cfoutput> </cfif> <br> </cfloop> I have a live (and slightly more elaborated) example here: (And since you refer to using cfloop, I am showing tags rather than cfscript, but the same applies to script.) But back to your report, I do agree that it seems the same logic used for handling emptyelements in those list functions (as updated in CF8) should be added for array functions (which process all elements in an array) as well as for cfloop when using the ARRAY or LIST attributes.
Comment by Charlie A.
30319 | February 18, 2019 03:34:16 PM GMT
Thanks, Charlie. I did land on the same workaround, and I was in fact using cfscript, but used CFLOOP so it was clear what I was referring to. Just for completeness, the ArrayEach() closure handles this correctly, allowing you to check each index element with IsDefined() to see if it's there. This at least spins the closure ArrayLen() times, every time.
Comment by Graham B.
30328 | February 19, 2019 04:55:36 PM GMT
Cool point, Graham (about arrayeach also helping). Thanks for the response.
Comment by Charlie A.
30329 | February 19, 2019 05:18:21 PM GMT