The random utterances of David Arno

ActionScript 3 variable scope: developers beware!

Consider, if you will, the following piece of non-language-specific code:

  void someMethod()
  {
    for (byte i=0; i<5; i++)
    {
      ...
    }
    for (int i=0; i<10; i++)
    {
      ...
    }
  }

If you are a C#, Java, C++ etc developer, such a piece of code might look decidedly unspectacular. Not so with ActionScript 3 (AS3) though as I recently discovered.

The equivalent in AS3 would be:

  function someMethod():void
  {
    for (var i:uint=0; i<5; i++)
    {
      ...
    }
    for (var i:int=0; i<10; i++)
    {
      ...
    }
  }

and this code won’t compile. Instead it will report an error due to variable i being redefined as a different type. Further, if you change i in the first loop to be an int too, the compiler will then issue a warning that you are redefining i.

Being used to languages such as Java, C# and C++, I put this down to a compiler bug, disabled what I thought was a pointless warning message in my projects and carried on happy I’d hidden an annoying bug. How wrong I was. I recently discovered a bug in my code was due to a variable defined inside a loop changing the value of a variable of the same name at the method-scope level. It turns out that AS3 doesn’t support block-level scope for variables. Variables can only have one of three scopes:

  • Global
  • Class
  • Function

Whilst a function-level variable can override a class-level one, variables defined inside code blocks (such as loops, try blocks etc) have method-level scope.

The following code illustrates how AS3 variable scoping works:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                layout="absolute" width="450" height="200"
                borderColor="0" borderStyle="solid"
                borderThickness="1" backgroundColor="#ffffff">
  <mx:Button x="20" y="10" label="Go" click="go()" fontSize="14"/>
  <mx:Label x="20" y="50" text="aVariable v1:" fontSize="14"/>
  <mx:Label x="20" y="90" text="aVariable v2:" fontSize="14"/>
  <mx:Label x="20" y="130" text="aVariable v3:" fontSize="14"/>
  <mx:Label x="20" y="170" text="aVariable v4:" fontSize="14"/>
  <mx:Label x="130" y="50" text="" fontSize="14" id="label1"/>
  <mx:Label x="130" y="90" text="" fontSize="14" id="label2"/>
  <mx:Label x="130" y="130" text="" fontSize="14" id="label3"/>
  <mx:Label x="130" y="170" text="" fontSize="14" id="label4"/>

  <mx:Script>
    <![CDATA[
      private var aVariable:String = "1";

      private function go():void
      {
        label1.text = ""+aVariable;

        var aVariable:int = 2;
        label2.text = ""+aVariable;

        for (var aVariable:int=3; aVariable<4; aVariable++)
        {
          label3.text = ""+aVariable;
        }

        label4.text = ""+aVariable;
      }
    ]]>
  </mx:Script>
</mx:Application>

Tracing through the code, I would have expected the following output:

  aVariable v1: 1
  aVariable v1: 2
  aVariable v1: 3
  aVariable v1: 2

The resultant SWF is included below. The results are really rather different:

This movie requires Flash Player 9

The version of aVariable defined in go() is in scope from the start of the method, so label1 picks up its default value, rather than the class-scoped variable’s value. And the loop uses the same variable, so label4 is 4, rather than 2.

For more information on AS3 variable scoping, I refer you to the “Understanding variable scope” section of Adobe’s official AS3 language reference.

You can download a zip of the FlexBuilder project used to create the above SWF here.


Share This Post...
No comments yet, click here to be the first

No comments yet. Be the first.

Leave a reply

Close