The problem is that slice() and concat() apparently only make true duplicates of the top level of an Array. So when you slice() off a 2D array, you end up with a genuine copy of that array - sure, sure - but what you've copied is really just a bunch of shallow references to the original.
Here's some code to try and make sense of it:
var sacred:Array = [ [0,1,2], [3,4,5] ];
var heretical:Array = sacred.slice();
heretical[0][0] = 99;
trace(heretical); //99,1,2,3,4,5
trace(sacred); //99,1,2,3,4,5
Mind you that if you alter the reference itself, say by changing the value of heretical[0] rather than going straight down to [0][0], you will have replaced the path to 'sacred' and heretical[0] will be thereafter wholly independent from sacred[0], such that any changes to heretical[0][0] will nolonger be reflected in 'sacred.'
It's a really old problem in Actionscript made new again by the Vector class brought in with Flash 10 and AS3. The Vector class is, after all, little more than a type-specified Array(), and so it is subject to the same slice() and concat() pitfalls. But in practice it's easy not to think of your Vectors as Arrays and that's how I managed to butt heads with slice() again today.
Here's an example of the slice issue using the Vector class:
var sacred:Vector.<Vector.<int>> = new Vector.<Vector.<int>>;
var heretical:Vector.<Vector.<int>> = new Vector.<Vector.<int>>;
var vInt:Vector.<int> = new Vector.<int>;
vInt.push(0,1,2, 3,4,5);
sacred.push( vInt.slice(0,3) );
sacred.push( vInt.slice(3,6) );
heretical = sacred.slice();
heretical[0][0] = 99;
trace(heretical); //99,1,2,3,4,5
trace(sacred); //99,1,2,3,4,5
Once you get deep into your own code - when your eyes have glossed over from too much trigonometry and micromanaging nested loops - it may not be immediately obvious to you that your Vector.<Vector.<int>> is, at end, an Array containing an Array containing some integers, or Array[Array[int]]. And that any duplication of that top level array really only passes along the inner array, which is still just a collection of references.
I don't know why Adobe hasn't provided a deep copy method for Arrays by now. I understand that the issue presented here isn't really a bug; that slice() is doing just what it says in the livedocs: Returning "a new array that consists of a range of elements from the original array, without modifying the original array." And that the shallow-references we end up with are the "elements" of the original array, as stated. Still, how many people have to bump their heads on the ceiling before Adobe integrates a method of really, truly, no shit, deep-copying an array? I suggest Array.noShitCopy();
0 comments:
Post a Comment