Thanks for looking at the problem and suggesting a workaround. - rod
--- In [email protected], "Gordon Smith" <[EMAIL PROTECTED]> wrote: > > > I forwarded this to a compiler engineer. > > He says that it looks like a compiler bug, but he thinks he found a > workaround: Don't name the three Function objects in verifyContainer(). > For example, instead of passing > > function myContainerFunction( itemNo : int, numItems : int, items : > Array ) : Boolean { ... } > > to enumerateItems(), pass > > function( itemNo : int, numItems : int, items : Array ) : Boolean { > ... } > > He said this seems to make it work. > > - Gordon > > ________________________________ > > From: Gordon Smith > Sent: Tuesday, March 27, 2007 8:55 PM > To: '[email protected]' > Subject: RE: [flexcoders] Re: Bad Results referencing local variables in > nested loops > > > I noticed two peculiarities in your code: You declare > myAnimationFunction() and myEventFunction() in verifyContainer() to > return void rather than Boolean. But when I declare them to return > Boolean and actually return true, I still see your problem. > > In stepping through it in the FlexBuilder debugger, it appears that the > scope chain is different when the second item is processed than when the > first one was. I think you've found an AS3 compiler codegen bug > involving nested anonymous functions. I'll forward this to a compiler > engineer. > > - Gordon > > ________________________________ > > From: [email protected] [mailto:[EMAIL PROTECTED] On > Behalf Of Rod Perkins > Sent: Tuesday, March 27, 2007 5:48 PM > To: [email protected] > Subject: [flexcoders] Re: Bad Results referencing local variables in > nested loops > > > > I had a typo in the post for a line in the setup function. The line: > > "[v:" + vItemNo + " i:" + itemNo + " a: " + aItemNo + " e: " + > eItemNo + "]" > > should be: > > "[v:" + pageNo+ " i:" + itemNo + " a: " + aItemNo + " e: " + eItemNo > + "]" > > - rod > > --- In [email protected] <mailto:flexcoders% 40yahoogroups.com> > , "Rod Perkins" <rperkins@> > wrote: > > > > > > I have been having a great time using ActionScript 3.0 and Flex > but > > I have encountered problems which seem to be caused by Flexbuilder > > or the Flashplayer runtime. The following problem is based on a > > situation I have in my application uses a data structure of > embedded > > objects. I replicated the problem using arrays instead of the > > classes I had used. The example may seemed contrived but > reproduces > > the problem without duplicating the complexity of my application. > > > > The structure was based on data structure of page objects, which > > contains several cell items. Each item has a list of animations, > > and each animation has a list trigger events references. So the > > nested structure looked like the following: > > > > Pages (instance 1) > > Item (instance 1) > > Animation (instance 1) > > Events (instance 1) > > Events (instance 2) > > Animation (instance 2) > > Events (instance 1) > > Events (instance 2) > > Item (instance 2) > > Animation (instance 1) > > Events (instance 1) > > Events (instance 2) > > Animation (instance 2) > > Events (instance 1) > > Events (instance 2) > > > > The setup function in my example creates this structure using > > arrays. The function "goodResult" traverses the structure using > > nested for-loops. Nested local variables at different scoping > > levels are referenced and displayed during the inner most loop for > > the Events (instance 1 & 2). This produces the expected result. > > Good Results > > 500 200 [v:0 i:0 a: 0 e: 0] > > 500 200 [v:0 i:0 a: 0 e: 1] > > 500 200 [v:0 i:0 a: 1 e: 0] > > 500 200 [v:0 i:0 a: 1 e: 1] > > 500 200 [v:0 i:1 a: 0 e: 0] > > 500 200 [v:0 i:1 a: 0 e: 1] > > 500 200 [v:0 i:1 a: 1 e: 0] > > 500 200 [v:0 i:1 a: 1 e: 1] > > > > The "badResult" function traverses the structure using the OO > > technique of enumeration (iterator) functions. Among other > reasons, > > I used this approach to make the code more readable and compact by > > hiding the loop from the caller and the typecasting the values > > automatically. The caller is required to send a Function which is > > then called during each pass (iterator) ofthe loop. The nested > > local variables this time are not displayed properly. During the > > first call, the results for Events (instance 1) is correct, but > > Events (instance 2) is incorrect. Subsequent calls to > > the "badResult" function display erroneous results. > > > > Bad Results - first iteration - first event loop good, second loop > > bad > > 500 200 [v:0 i:0 a: 0 e: 0] > > 500 200 [v:0 i:0 a: 0 e: 1] > > 500 200 [v:0 i:0 a: 1 e: 0] > > 500 200 [v:0 i:0 a: 1 e: 1] > > 500 59369881 [v:0 i:1 a: 0 e: 0] > > 500 59369881 [v:0 i:1 a: 0 e: 1] > > 500 59369881 [v:0 i:1 a: 1 e: 0] > > 500 59369881 [v:0 i:1 a: 1 e: 1] > > Bad Results - second iteration - both loops bad > > 2 500 [v:0 i:0 a: 0 e: 0] > > 2 500 [v:0 i:0 a: 0 e: 1] > > 2 500 [v:0 i:0 a: 1 e: 0] > > 2 500 [v:0 i:0 a: 1 e: 1] > > 2 500 [v:0 i:1 a: 0 e: 0] > > 2 500 [v:0 i:1 a: 0 e: 1] > > 2 500 [v:0 i:1 a: 1 e: 0] > > 2 500 [v:0 i:1 a: 1 e: 1] > > Bad Results - third iteration - both loops bad > > 2 500 [v:0 i:0 a: 0 e: 0] > > 2 500 [v:0 i:0 a: 0 e: 1] > > 2 500 [v:0 i:0 a: 1 e: 0] > > 2 500 [v:0 i:0 a: 1 e: 1] > > 2 500 [v:0 i:1 a: 0 e: 0] > > 2 500 [v:0 i:1 a: 0 e: 1] > > 2 500 [v:0 i:1 a: 1 e: 0] > > 2 500 [v:0 i:1 a: 1 e: 1] > > > > I don't know if the problem is with the enumeration function calls > > or stack references during nested scope (this is not recursion so > > the stack depth should not be that great). The example is simple > so > > you can play around with it. It does make me worry about using > > Functions or nested function calls. > > > > Here is the code for the example. > > > > Regards, > > > > Rod Perkins > > > > --------------------------- > > package > > { > > > > import flash.display.Sprite; > > import flash.events.Event; > > > > public class BuildError_2 extends Sprite > > { > > private var _pages : Array = new Array(); > > > > public function enumerateEvents( _events : Array, func : > > Function ) : void > > { > > for ( var x : int = 0, numItems : int = > > _events.length; x < _events.length; x++) > > { > > var eventObj : Object = Object( > > _events[x] ); > > if (func.call( this, x, numItems, > > eventObj ) == false) break; > > } > > } > > > > public function enumerateAnimations( _anim : Array, func : > > Function ) : void > > { > > for ( var x : int = 0, numItems : int = > > _anim.length; x < _anim.length; x++) > > { > > var animObj : Object = Object( _anim > > [x] ); > > if (func.call( this, x, numItems, > > animObj ) == false) break; > > } > > } > > > > public function enumerateItems( _items : Array, > > func : Function ) : void > > { > > for ( var x : int = 0, numItems : int = > > _items.length; x < numItems; x++) > > { > > var itemObj : Object = _items[x]; > > if (func.call( this, x, numItems, > > itemObj ) == false) break; > > } > > } > > > > > > public function setup() : void > > { > > _pages = new Array(); > > for ( var pageNo : int = 0; pageNo < 1; > > pageNo++) > > { > > var _items : Array = new > > Array(); > > for ( var itemNo : int = 0; > > itemNo < 2; itemNo++) > > { > > var _anim : Array = > > new Array(); > > for ( var aItemNo : > > int = 0; aItemNo < 2; aItemNo++) > > { > > > > var > > _events : Array = new Array(); > > for ( var > > eItemNo : int = 0; eItemNo < 2; eItemNo++) > > { > > > > > > _events.push( > > > > "[v:" + vItemNo + " i:" + itemNo + " a: " + aItemNo + " e: " > > + eItemNo + "]" > > ); > > } > > _anim.push( > > _events ); > > } > > _items.push( _anim ); > > } > > _pages.push( _items ); > > } > > } > > > > public function verifyContainer( container : > > Array ) : void > > { > > enumerateItems > > ( > > container, > > function myContainerFunction( > > itemNo : int, numItems : int, items : Array ) : Boolean > > { > > var itemCount : int = 500; > > > > enumerateAnimations > > ( > > items, > > function > > myAnimationFunction( animNo : int, numItems : int, anim : > Array ) : > > void > > { > > var > > animationDuration : int = 200; > > > > > > enumerateEvents > > ( > > anim, > > > > function myEventFunction( eventNo : int, numItems : int, > > event : Object ) : void > > { > > > > trace( itemCount + " " + animationDuration + " " + event); > > } > > ); > > } > > ); > > > > return true; > > } > > ); > > > > } > > > > public function goodResults() : void > > { > > for ( var pageNo : int = 0; pageNo < > > _pages.length; pageNo++) > > { > > var _items : Array = _pages[ > > pageNo ] as Array; > > for ( var itemNo : int = 0; itemNo < > > _items.length; itemNo++) > > { > > var itemCount : int = 500; > > > > var _anim : Array = _items[ > > itemNo ] as Array; > > for ( var aItemNo : int = 0; > > aItemNo < _anim.length; aItemNo++) > > { > > > > var > > animationDuration : int = 200; > > > > var _events : Array > > = _anim[ aItemNo ] as Array; > > for ( var eItemNo : > > int = 0; eItemNo < _events.length; eItemNo++) > > { > > > > trace( > > itemCount + " " + animationDuration + " " + _events[eItemNo] ); > > } > > } > > } > > } > > } > > > > public function badResults() : void > > { > > for ( var index : int = 0; index < > > _pages.length; index++) > > { > > var container : Array = _pages > > [index] as Array; > > > > verifyContainer( container ); > > } > > } > > > > public function BuildError_2() > > { > > setup(); > > > > trace("Good Results" ); > > // this path will print good results > > // 500 200 > > // 500 200 > > // 500 200 > > // 500 200 > > // 500 200 > > // 500 200 > > // 500 200 > > // 500 200 > > goodResults(); > > > > trace("Bad Results - first iteration - first > > event loop good, second loop bad" ); > > // this path will print bad results > > // 500 200 > > // 500 200 > > // 500 200 > > // 500 200 > > // 500 59435417 > > // 500 59435417 > > // 500 59435417 > > // 500 59435417 > > badResults(); > > > > trace("Bad Results - second iteration - both > > loops bad" ); > > // this path will print worse results > > traversing the same structure > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > badResults(); > > > > trace("Bad Results - third iteration - both > > loops bad" ); > > // this path will print the same results as > > the second iteration > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > // 2 500 > > badResults(); > > } > > } > > } > > > > Rod Perkins > > Principle Architect & Designer > > Yahoo! Inc. > > 701 First Avenue > > Sunnyvale, CA 94089 > > 408.349.2766 (tel) > > 409.349.7170 (fax) > > rperkins@ > > >

