Tuesday, 25 March 2014

myArray.each()... extending the array whilst iterating..?

G'day:
I dunno what to think about some behaviour I'm seeing when iterating over an array with the .each() method.

Consider (but do not run!) this code:

numbers = ["one","two","three","four"];
numbers.each(function(value,index){
    if (value=="one") {
        numbers.append("five");
    }
    writeOutput("Index: #index#; value: #value#<br>");
});
writeDump(var=numbers);


What would you expect the result to be? One might expect four iterations because the array to iterate is only evaluate at the outset of the loop; or one might expect five iterations because by the time we get to the fourth element, there is now a fifth element. Either of these would be legit behaviour to me.

On Railo I get this:

Index: 1; value: one
Index: 2; value: two
Index: 3; value: three
Index: 4; value: four

Array
1
stringone
2
stringtwo
3
stringthree
4
stringfour
5
stringfive

But on ColdFusion I get this:

Index: 1; value: one
Index: 2; value: two
Index: 3; value: three
Index: 4; value: four
Index: 5; value: five

array
1one
2two
3three
4four
5five

Railo takes the former approach: the iterations to be done seem to be calculated at the beginning of the loop, not each iteration; whereas ColdFusion takes the approach of simply iterating over whatever array is there.

Hmmm. What I do know is that both should do the same thing! CFML should be consistent in areas were both vendors implement the same thing!

To add more question marks, I ran this JS version:

numbers = ["one","two","three","four"]
numbers.forEach(function(value,index,array){
    if (value=="one") {
        numbers.push("five")
    }
    console.log("Index: "+ (index+1) + "; value: "+ value)
})
console.log(numbers)

And that resulted in this:

Index: 1; value: one
Index: 2; value: two
Index: 3; value: three
Index: 4; value: four
["one", "two", "three", "four", "five"]


And this code on Ruby:

numbers = ["one","two","three","four"]
numbers.each_with_index { |value,index|
    if value=="one" then
        numbers.concat ["five"] 
    end

    puts "Index: %d; value: %s" % [index+1,value]
}

Which yielded this:

Index: 1; value: one
Index: 2; value: two
Index: 3; value: three
Index: 4; value: four
Index: 5; value: five
["one", "two", "three", "four", "five"]


So JS does the same as Railo; Ruby the same as ColdFusion.

I like the Ruby / ColdFusion way better, I think.

Thoughts?

--
Adam