Making use of the Scope Chain in Flash MX

Parametrized functions, Static properties and methods and Private properties

- By Timothée Groleau -

First published on 9 April 2003

Introduction

In a previous paper, we have seen that using nested functions in Flash MX can lead to memory waste. While this is true, there are also plenty of things we can do using nested functions and the activation object persistence behavior. In this paper, we'll go through parametrized functions, an enhanced version of Object.addProperty, an implementation of static properties and methods in ActionScript OOP and finally a discussion on private properties.

In this paper, you are expected to have a fairly good understanding of actionscript and general OOP practices. Reading the previous paper would also definitely help.

At the end of this articles, there will be a downloadable library file with the code discussed.

 

Translations

[Updated on 02 September 2003]

Jun Kitazawa from Bascule Inc. has kindly translated this page in japanese. The translation is available at: http://faces.bascule.co.jp/private_static.html.

 

Acknowledgment

Most of what I know in ActionScript OOP, I read it from Robin Debreuil's online book and Dave Yang's Quantumwave's Flash section. The first thing I read on private properties in ActionScript was this post from Tatsuo Kato on the FlashCoders list.

 

Parametrized functions

Imagine you want to have a bunch of movie clips on stage and you want all of them to move uniformly in random directions (each movie clip follows a line) and loop on the stage. For some reason, you don't want to create a subclass to handle that behavior but instead you have your code in a centralized place and you need to initialize all your movie clips from there.

Typically, to have the movie clips moving around independently, they need to each move a bit at each frame, both along x and y axis. Since onEnterFrame is broadcasted without parameters, you can't use the event to pass different parameters to each movie clip so they'd move independently, you need to store the xStep and yStep in each of the movie clip and make the onEnterFrame handler perform an action based on these values. Typically, the code would look like this (assuming 10 movie clips):

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
move = function() {
  // using the property of the mc
  this._x += this.xStep;
  this._y += this.yStep;

  if (this.xStep > 0) {
    if (this._x > Stage.width) this._x = 0;
  } else {
    if (this._x < 0) this._x = Stage.width;
  }
  if (this.yStep > 0) {
    if (this._y > Stage.height) this._y = 0;
  } else {
    if (this._y < 0) this._y = Stage.height;
  }
}

for (var i=0; i<10; i++) {
  o = this["mc" + i];

  // setting the properties in the mc
  o.xStep = Math.random() * 50 - 25;
  o.yStep = Math.random() * 50 - 25;
  o.onEnterFrame = move;
}

Now what if you just don't want to have to pre-store the step values in each movie clip? Say what you want is not to assign a general function to all the movieclips that are based on the movieclip's parameters; instead, you want to be able to assign a parametrized function to a movieclip that will magically act as you wish

Using the scope chain can do that. We can create a function that will store some parameters in the activation object and then return a newly created function. That way the movie clip stays clean, and we probably gain some speed because accessing "this.xStep" will be just a little bit slower than just retrieving "xStep" in the scope chain.

The code could look like this:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
getMoveFunction = function() {
  var xStep = Math.random() * 50 - 25;
  var yStep = Math.random() * 50 - 25;

  return function() {
    this._x += xStep;
    this._y += yStep;
    if (xStep > 0) {
      if (this._x > Stage.width) this._x = 0;
    } else {
      if (this._x < 0) this._x = Stage.width;
    }
    if (yStep > 0) {
      if (this._y > Stage.height) this._y = 0;
    } else {
      if (this._y < 0) this._y = Stage.height;
    }
  }
}

for (var i=0; i<10; i++) {
  // get a parametrized function
  this["mc" + i].onEnterFrame = getMoveFunction();
}

If you decide to go for such an option, remember that each of the 10 movie clip carries its own unic function which DOES take space in memory.

Although the parametrized onEnterFrame function is slightly faster than in the previous example, simple tests show that the speed difference is really minimal so let's not emphasize on that too much. Just think whether parametrized functions can be useful for you, regardless of speed consideration.

Just for information, in both cases, to gain some speed, we could use separate functions based on the conditions and the signs of xStep and yStep instead of doing the tests inside the function itself.

Also, the example above is not so good in the sense that the parameters for the internal function are generated randomly inside the outer function. Just keep in mind that you could pass parameters when calling "getMoveFunction()" so you could really control how the parametrized function would behave.

 

Object.AddProperty2

One great feature of Flash MX is Object.addProperty. It allows you to create a virtual property for which a getter and a setter functions are called transparently when the virtual property is accessed or assigned a value. In many cases, when you publish a virtual property for an object you still need to store an internal value inside the object and you don't want any developer to handle that internal value directly.

A typical example of usage for addProperty should be like this (this one is very dumb but never mind):

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
getter = function() {
  // dummy operation to show the use of the getter function
  return Math.round(this.$internalProp * this.factor); 
}
setter = function(val) {
  this.$internalProp = val;
}

obj = {};
obj.addProperty("theProp", getter, setter);
obj.factor = 3;
obj.theProp = 4.12355;
trace(obj.theProp); // 12
Output:

12

The probem is that ActionScript does not allow private properties so anybody could just access the internal property "$internalProp" directly and bypass the getter/setter of the virtual property. This can be a problem.

This is when the scope chain can come to the rescue once again! If we are willing to add 2 more constraints on the getter and setter functions, we can use nested functions to store the internal property in the activation object of the outer function. Since there is not link to the activation object of the outer function anywhere but in the scope chain of the inner function(s), nobody could access the internal value.

The 2 extra constraints are:

  • the setter must return the value to store as the internal property
  • the getter must get the internal value as its parameter.

Seems reasonable right? Here is the code for a addProperty2 implementation:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
Object.prototype.addProperty2 = function(name, getter, setter) {
  var prop;
  this.addProperty(name, 
          function() {
            return getter.call(this, prop);
          },
          function(val) {
            prop = setter.call(this, val);
          }
        );
}
ASSetPropFlags(Object.prototype, "addProperty2", 1);

With that code, the getter and setter can still reference the current object from the reference "this", so public properties are still accessible, assuming the code above is in the flash file, the following is a test script:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
getter = function(internalValue) {
  return Math.round(internalValue * this.factor);
}
setter = function(val) {
  return val;
}

obj = {};
obj.addProperty2("theProp", getter, setter);
obj.factor = 3;
obj.theProp = 4.12355;
trace(obj.theProp); // 12
Output:

12

In the script above the internal value is buried in the scope chain and is not accessible to any external script. The problem is that because it is buried, it is not even accessible to the object itself so in the end, even it has to use the virtual property. May be good, may be bad, see if that can work for you.

Another problem with the code above is that you can't use addProperty2 to create a virtual property on a whole class. Using the standard addProperty, when the internal value was stored in the instance itself using the reference "this", we could define the virtual property in the prototype of a class and each instance would carry its own internal value. With addProperty2, since the value is not specific to an instance but is buried in the scope chain, adding a virtual property to a class' prototype will create a property that is affected for all instances, if any instance changes it.

Hey wait a minute, doesn't that sound like the description of a static property? Pretty close :), and we'll go ahead to create a static property using the scope chain in a minute. For now, just remember that addProperty2 must be used independently on EVERY instance if you really want a private internal value so it may not be very efficient. Again, you decide whether you can find a good use for it or not. Good luck!

 

Static properties

The bit of code above gave us a pretty good insight of where we are going. But before we carry on, lets do a quick OOP reminder. In this section, I will always use "static" to mean "public static" of Java.

What are static properties?

A Static property is a property that belong to a class rather than to an instance. It means that given a class, a static property can be accessed without creating an instance of that Class.

In Java, a static property is also accessible from the instances of the class themselves. if one instance changes the value of a static property, then all the instances of that class and the class itself will reflect the change.

For instance, below is a little java code which illustrates the static behavior:

Code (JAVA):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Test
{
  public static int theInt = 5;

  public static void main(String[] args) {
    Test t1 = new Test();
    Test t2 = new Test();

    System.out.println(Test.theInt); // 5
    System.out.println(t1.theInt); // 5
    System.out.println(t2.theInt); // 5

    System.out.println("===");

    Test.theInt = 6; // modifying from the class

    System.out.println(Test.theInt); // 6
    System.out.println(t1.theInt); // 6
    System.out.println(t2.theInt); // 6

    System.out.println("===");

    t1.theInt = 7; // modifying from an instance

    System.out.println(Test.theInt); // 7
    System.out.println(t1.theInt); // 7
    System.out.println(t2.theInt); // 7
  }
}
Output:

5
5
5
===
6
6
6
===
7
7
7

 

How about ActionScript?

In ActionScript unfortunately, there isn't anything close to that. Adding a property in a class' prototype can't work because setting the property from an instance will not be reflected in the other instances (see Robin Debreuil's explanation) and the property is not accessible from the class itself.

What most people have been doing is to add a property to the class itself to ensure that the property exists only in one location. Subsequently, to access the property from a method, either a hardcoded reference to the class must be made or from an instance, the property can be accessed using "this.constructor.theProperty". Unfortunately, this is not as flexible as JAVA and it breaks when doing inheritance if the static property belongs to the superclass.

Once again, the scope chain comes handy. With the scope chain, we can have a unique secured location to create a property. Then, publishing a virtual property for both the class and the class' prototype does the trick. Check out the code below and the test case after it:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
Function.prototype.addStaticProperty = function(name, prop) {
  var getter = function() {
    return prop;
  }
  var setter = function(val) {
    prop = val;
  }

  this.addProperty(name, getter, setter);
  this.prototype.addProperty(name, getter, setter);
}
ASSetPropFlags(Function.prototype, "addStaticProperty", 1);

Test case (assuming the code above exists in the movie):

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Test = function() {}
Test.addStaticProperty("theInt", 5);

t1 = new Test();
t2 = new Test();

trace(Test.theInt); // 5
trace(t1.theInt); // 5
trace(t2.theInt); // 5

trace("===");

Test.theInt = 6;

trace(Test.theInt); // 6
trace(t1.theInt); // 6
trace(t2.theInt); // 6

trace("===");

t1.theInt = 7;

trace(Test.theInt); // 7
trace(t1.theInt); // 7
trace(t2.theInt); // 7
Output:

5
5
5
===
6
6
6
===
7
7
7

So using addStaticProperty, the behavior is the same as in Java and as you can see, there is no pollution: the internal value is kept in the activation object and is not accessible from anywhere. Another good thing is that the memory usage is not too bad since the activation object exists only once for the whole class.

Of course it'd be too good if it worked exactly like in Java but unfortunately, there is still one problem with inheritance. While the static property will still be accessible from the subclass instances, it won't be accessible from the subclass itself and this can be problematic. The code below demonstrate it:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SuperTest = function() {};
SuperTest.addStaticProperty("prop", 5);

Test = function() {};
Test.prototype = new SuperTest();

t1 = new Test();
t2 = new Test();

trace(t1.prop); // 5
trace(t2.prop); // 5

trace("===");

t1.prop = 6;

trace(t1.prop); // 6
trace(t2.prop); // 6

trace("===");

trace(SuperTest.prop); // 6
trace(Test.prop); // undefined
Output:

5
5
===
6
6
===
6
undefined

Line 23 shows that the static property cannot be accessed from the subclass. To solve this issue, we have to create a link between the SubClass function and the SuperClass function. The fastest way to do that is to set the __proto__ property of the subClass to the superClass. Since both the subClass and the superClass are instances of functions, the class method of functions (call, apply, etc.) can still be accessible in the subClass.

So what we need now is to build a custom method to set up the inheritance chain AND link the 2 classes together. Using a custom method to set the inheritance chain instead of setting the chain manually for each class also has one extra major advantage. Indeed, with that, we will also able to choose what method of inheritance we want to implement and we will be able to change it very easily should we have too (client's requirement for instance). For more detail about that, check this post by Dave Yang.

So here is the custom extends munction that we need to use:

Code:
1
2
3
4
5
Function.prototype.cExtends = function(SuperClass) {
  this.prototype = new SuperClass();

  this.__proto__ = SuperClass;
}

Or if you are not happy with the recommended inheritance style, you can use the rebel alliance way of inheritance (my favorite, check out this article from Dave Yang for more details). That's the good thing about using a custom extends function, you can change the implementation very easily. Here is the rebel alliance way:

Code:
1
2
3
4
5
6
7
Function.prototype.cExtends = function(SuperClass) {
  this.prototype.__proto__ = SuperClass.prototype;
  this.prototype.__constructor__ = SuperClass;
  ASSetPropFlags(this.prototype, "__constructor__", 1);
	
  this.__proto__ = SuperClass;
}

And that's it, if you replace the line "Test.prototype = new SuperTest();" by "Test.cExtends(SuperTest);"in the sample above, you'll see it works just fine. The reason I name the function cExtends is because extends is a reserved word in ECMAScript so "cExtends" stands for "custom-Extends".

OK, It seems to work alright but I haven't tested it extensively so it may just break in some instances. Please let me know if you encounter problems with that.

Side Note: The "rebel alliance" is a very informal name that has been around for some time on the FlashCoders' list (I think Dave Yang came up with that name but I'm not sure). It describes people who prefer to use "__proto__" to set up the inheritance chain instead of the traditional method with "new SuperClass();". It started in Flash 5 where doing the traditional inheritance was buggy and people didn't like creating a dummy instance of the superClass in the subClass' prototype chain. We thought that the rebel alliance would die with Flash MX because it broke the new MX feature "super" and the bug in the traditional method was fixed. However the issue on the dummy instance was still there and thankfully, Peter Edwards found the solution for the rebel alliance with the undocumented reference "__constructor__". See his post. Long live the rebel alliance ! :)

 

Static methods?

Similarly to static properties, static methods are methods that can be called from a class directly without creating a instance of that class. In Java a static method can also be called from the instances of the class themselves.

A static method can not access any of the instance properties using the "this" reference. Try putting "this" in a static method in Java and you'll get the following compilation error: "non-static variable this cannot be referenced from a static context".

However a static method can access the static properties of the class (makes sense right?). We could assign a function directly to a class and the class' prototype but then the calling scope would be different and the reference "this" would change for each function.

We could also use the function addStaticProperty above to assign a function to a static property so it'll act as a method but by doing this, none of the static properties would be accessible from the static method. That would make the method kind of useless: it could not access any of either the static or instance properties and would have to be a completely stand-alone method.

We can make a static method by adding a new constraint. Basically, we will need the static method to use the reference "this" as a reference to the class itself. From that reference, the method will be able to access the static properties.

Below is a piece of code that demonstrate how to add a static method:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function.prototype.addStaticMethod = function(name, theFunc) {
  var _theClass = this;

  var getter = function() {
    return theFunc;
  };
  var setter = function(meth) {
    theFunc = function() {
      return meth.apply(_theClass, arguments);
    };
  };
  setter(theFunc);

  this.addProperty(name, getter, setter);
  this.prototype.addProperty(name, getter, setter);
}
ASSetPropFlags(Function.prototype, "addStaticMethod", 1);

As you can see, it's a little bit more complicated to handle a static method and we now have three levels of nested functions. Neverthless, it works alright and here is a test script (assuming both addStaticProperty and addStaticMethod exit in the movie):

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
41
42
43
Test = function() {};
Test.addStaticProperty("prop1", 5);

t = new Test();
t.prop2 = 15;

trace(t.prop1); // 5
trace(t.prop2); // 15

theMeth = function(arg1, arg2, arg3) {
  trace("arg1: [" + arg1 + "] - " + 
      "arg2: [" + arg2 + "] - " + 
      "arg3: [" + arg3 + "] - " + 
      "this.prop1: [" + this.prop1 + "] - " + 
      "this.prop2: [" + this.prop2 + "]");
}

// ading the static method
Test.addStaticMethod("meth", theMeth);

trace("===");

// testing with parameters
t.meth("hello", "there", "tim");
Test.meth();

trace("===");

t.prop1 = 6;

t.meth();
Test.meth();

trace("===");

// overwriting the static method
Test.meth = function(arg) {
  trace(arg + " - " + this.prop1);
}

t.meth("hello");
Test.meth();
Output:

5
15
===
arg1: [hello] - arg2: [there] - arg3: [tim] - this.prop1: [5] - this.prop2: []
arg1: [] - arg2: [] - arg3: [] - this.prop1: [5] - this.prop2: []
===
arg1: [] - arg2: [] - arg3: [] - this.prop1: [6] - this.prop2: []
arg1: [] - arg2: [] - arg3: [] - this.prop1: [6] - this.prop2: []
===
hello - 6
- 6

This code shows that the parameters are passed properly and that the static properties can be retrieved from the static method using the reference "this". Remember: "this" in the static method does NOT represent an instance of the class; it represents the class itself. Also, line 37 shows that the static method can be overwritten like any normal method.

That said, the static method suffers from the same problem as the static property: with inheritance, the static method cannot be retrieve from the subclass so again you have to use the "cExtends" method to set up the inheritance.

To be honnest, I can't really see the need for java-style static methods in ActionScript but since it seems it can be implemented, I thought I'd mention it. If you can find some good use for that let me know.

I think on the other hand that static properties is pretty good to have.

 

Private properties

In Java, a private property is a property that can be manipulated by the instance but not by any other external script. ActionScript in Flash MX cannot handle true private properties. However, using the scope chain and nested functions, we can create properties that reside in the activation object of the outer function so that they become hidden to any script. The only way to access the properties is use them in the inner functions later on. This can't really be labelled private properties but it creates a protection mechanism, similar to private properties.

As we mentionned before, once a value is kept in the scope chain of a function, then it becomes hidden to everything including the object that holds the function. Because of that it can't be really useful. Especially if you need to access the raw internal value from different function and you need to bypass the getter/setter from the object itself (not from external scripts obviously).

The best way I can think of, to create useful such private properties, is to create ALL the private properties using the activation object of the class itself. That way, all the private properties would exist in the same activation object. Because of that, the getter/setter for each private property will be able to access all the other private properties (by not using an explicit scope). And, on top of that, the getters/setters would also be able to retrieve the public properties using the reference "this".

On the downside, the public methods would still not be able to access the private properties and would have to use the getters/setters. Also, each instance of the class will carry unique getters/setters for each private property. If many instances are created from a class that implement private properties, it could be a killing overhead.

In any case, here is sample code below:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
theClass = function(name, age) {
  // age is a public property
  this.age = age;

  // name is a private property
  this.getName = function() {
    return name;
  }
  this.setName = function(val) {
    name = val;
  }

  // we can add another private property
  var hairColor;
  this.getHairColor = function() {
    trace(name +
      " has " + hairColor + " hair and is " + this.age + " years old.");
    return hairColor;
  }
  this.setHairColor = function(val) {
    hairColor = val;
  }
}

p = new theClass("Tim", 25);
p.setHairColor("brown");
h = p.getHairColor();
Output:

Tim has brown hair and is 25 years old.

In the code above, you can see how all the getters/setters can access all the private and public properties, the method "getHairColor" can access both "hairColor" and "name", which are private properties, and "age", which is a public property.

Doing this, you can actually create many private properties in the activation object but it is not required to create a getter and setter for each. In fact, you are not restricted to getters and setters at all, you can stick in the constructor any method that will need to have direct access to the private properties. However, always keep in mind that the more methods you put in the constructor, the more memory it will use because each instance will carry its own version of the method.

If you are not too concerned about having the private properties accessible to each other, and just want to add a private property to any object quickly, regardless of its class, you can use addProperty2 (see above) to add a virtual property. If you don't want a virtual property but want to force the use of getter/setter, you could use the following code to add a private property and its associate getter and setter methods to any object (the 2 extra constraints introduced for addProperty2 still apply):

Code:
1
2
3
4
5
6
7
8
9
10
11
Object.prototype.addPrivateProperty = function(name, getter, setter) {
  var prop;
  this["get" + name] = function() {
      return getter.call(this, prop);
  };

  this["set" + name] = function(val) {
      prop = setter.call(this, val);
  };
}
ASSetPropFlags(Object.prototype, "addPrivateProperty", 1);

See the code below to see how it works (especially useful for older women):

Code:
1
2
3
4
5
6
7
8
9
10
11
getter = function(internalVal) {
  return internalVal / 2;
}
setter = function(val) {
  return val;
}

aWoman = new Object();
aWoman.addPrivateProperty("age", getter, setter);
aWoman.setAge(42);
trace(aWoman.getAge()); // 21
Output:

21

Remember that by using this addPrivateProperty function, if you create 2 private properties for the same object, each private property is stuck in its own activation object and each private properties cannot be accessed directly from the getter/setter of the other property. Only the getters/setters themselves can be used. Again, maybe it's good, maybe it's bad, I hope you can something useful to do with this.

As far as I am concerned, If I really need private property, I will probably stick to the implementation using the activation object of the constructor.

 

Conclusion

OK, that'll be it. In this paper, we have seen how we can make use of the scope chain and the nested function behavior, specifically we have seen how to create parametrized function, how to add static properties and methods to a class and how to create pseudo private properties.

To be honnest, I do not have a single real world application where I used any of what we discussed :p . However, I'd say there is potential at least for the static property implementation. On top of that, I just enjoyed working on this topic so I thought I'd just share my code. You can download below an actionscript library file which contains the methods cExtends, addStaticProperty, addStaticMethod, addProperty2 and addPrivateProperty.

If you use the private properties feature, either with addProperty2, in the constructor or using addPrivateProperty, keep in mind the overheads in term of memory usage. For instance, using the constructor to create 10 private properties with 10 getter/setter (20 functions) per instance will not be very efficient if you need to create 100 instances. Clearly, in such case you would have to consider whether implementing private properties is really crucial for your application.

If you manage to use any of the various bits of code above to build something useful, drop me a note, I'd be delighted to know. Also, if you spot any mistake in this page on the code, english, etc. or just want to share a thought, please feel free to email me.

Here is the file:

static_private.as

 


Last modified on:

File size: