A Nifty AS3 State Trick

January 1st, 2009

I was working on an AS3 class that had a state that needed to be reset every once and a while to some arbitrary original state. It turned out to be an interesting problem. The easy solution of course, is to store the original values into secondary properties and use these values to restore the original state.

public class Example {
  private var _originalX:Number;
  private var _originalY:Number;
  private var _x:Number;
  private var _y:Number;
  public function Example(x:Number, y:Number) {
    _originalX = x;
    _originalY = y;
    reset();
  }
  private function reset():void {
    _x = _originalX;
    _y = _originalY;
  }
  public function doSomething():void {
    reset();
  }
}

Since I was going to do this whole state thing for more classes, and because I felt there had to be an easier way, I went looking for a better solution.

First I thought I could write a function that stored all the properties when called, so it could restore them later. This couldn’t work because not all the properties should be reset. I considered adding a list of properties that should be stored (or not stored), so it would only reset the values I choose.

This solution still seemed imperfect, since creating a large list of state properties was just as annoying as the easy solution, and offered no compiler errors if I made any mistakes. In addition it wouldn’t work for more complex situations like this one.

public class Example extends State {
  private var _rect:Rectangle;
  private var _speed:Number;
  public function Example(rect:Rectangle, speed:Number) {
    _rect = rect;
    _speed = speed;
    // The properties of _rect will not be stored, just the _rect itself
    store("_rect", "_speed");
  }
  public function doSomething():void {
    reset();
    // _rect is unchanged
  }
}

My ideal solution seems so obvious now. It can handle more complex state details, offers nice compiler errors when I make a mistake, and only adds about four extra lines of code to the whole class. Simply use an anonymous function in the constructor as a way of storing the original state so it can be called again later.

public class Example {
  private var _speed:Number;
  private var _rect:Rectangle;
  private var reset:Function;
  public function Example(rect:Rectangle, speed:Number) {
    reset = function():void {
      _rect = rect.clone();// I'm assuming that the original rect doesn't change here
      _speed = speed;
    }
    reset();
  }
  public function doSomething():void {
    reset();
  }
}

I can’t think of many flaws, its main problem is that it does not play well with OOP, since the function must be anonymous and cannot be overridden. Subclasses can still implement this it independently or work together, it’s just not OO by default. It’s probably not going to save any extra memory either, but I wasn’t paticularly concerned about that.

Also, I think it’s important to avoid using the “this” keyword in the anonymous function (or any anonymous function for that matter) since what “this” is can change. For reasons unknown to me, properties accessed without using “this” (like in the example above) always reference the original. Calls however, do not appear to do this.

This could be considered more trouble than its worth, but it didn’t just simplify my code, it turned out to be invaluable as a way to manage the state of the classes I was working with later.

4 Responses to “A Nifty AS3 State Trick”

  1. sakri Says:

    Nifty indeed. Like you, I’m a little thrown off by the business of storing the parameters of the constructor. Are these parameters stored in the anonymous function, or do constructor parameters (or any other parameters) hang around in memory longer than expected? The first option would be “nifty”, the second would be a bit scary. I wonder if decompiling would give some insight… Cheers for posting that!

  2. Kelvin Luck Says:

    I like it 🙂 Nice use of the closure – I’m sure this approach could be useful in other situations too… It may not be too OO but sometimes it is good to remember the dynamic and functional features of actionscript and use them to our advantage 🙂 And I guess if reset was declared as protected then you could override it in subclasses by simply defining it differently (although you wouldn’t be able to call super.reset())

  3. Tronster Says:

    Thanks for this post. It’s an interesting way to organize a reset to default values. The lack of nice play with OO is a big short-coming, but either way its got me thinking.

    sakri: I agree; I hope on Monday to try this out at work where I have access to a decompiler and see what it looks like.

  4. henrique matias Says:

    When you create a function, the scope of the vars are stored within the function, an carried forever.

    I remember to read an article about this, but i lost it on my delicious (what a mess!)…

    The fact is, that when you do a “call” if you dont specify a scope, it will be “undefined”, and consequently “this” will be undefined too.

    Here you can found something about it, but is not exactly the article that i said…

    http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000057.html

    “Methods behave similarly in that they also retain information about the lexical environment in which they were created”

    cheers

Leave a Reply