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)
[EMAIL PROTECTED]




Reply via email to