Typesafe Enum Pattern in AS3

ActionScript, Design Patterns, Flash, Flex Add comments

I was trying to create a typesafe enum today to hold a Debit and Credit value and realized it could not that easily be done in AS3. In AS2 or in Java (prior to Java 5 when there was no enum construct) you could do the trick by making the constructor of the enum private and instantiate the values as static constants. (See this blog post for an AS2 example.)


Unfortunately there is no such thing as a private constructor in AS3, so we need to find another way of restricting values. First thing I thought of was to use the internal class "hack" used to create singletons to ensure that instantiation can only happen internally in the enum class. However that does not work (probably since the internal class is not yet loaded when trying to instantiate the values). Here's an example.

Actionscript:
  1. package com.domain {
  2.   class DebitCreditEnum {
  3.     public static const DEBIT:DebitCreditEnum = new DebitCreditEnum("debit", new EnumRestrictor());
  4.     public static const CREDIT:DebitCreditEnum = new DebitCreditEnum("credit", new EnumRestrictor());
  5.    
  6.     private var _name:String;
  7.  
  8.     public function DebitCreditEnum(name:String, restrictor:EnumRestrictor) {
  9.       Assert.notNull(restrictor, "The 'restrictor' argument must not be null"); //*
  10.       _name = name;
  11.     }
  12.   }
  13. }
  14. internal class EnumRestrictor {}

(* the Assert class is part of the Prana Framework)

The example above throws the following error:

TypeError: Error #1115: private::EnumRestrictor is not a constructor.
at com.domain::DebitCreditEnum$cinit()
at [newclass]
at global$init()

Apparently, it is impossible to call the constructor of the inner class in a static member of the top class. This also means that we can't create eagerly loaded singletons with the inner class approach. I can imagine that this makes sense in a way, since the inner class will probably be loaded after the top class has loaded and its static members have been initialized. However, I'm not sure about this, so if anyone knows feel free to comment on this.

Static code block to the rescue

AS3 introduces the concept of a static code block. The code inside this block will be executed when the class is loaded in memory. This happens before a constructor call and after all static members have been set. Using a static code block, we can restrict access to the constructor by setting a flag after we have defined the values for our enum. Here's the example:

Actionscript:
  1. package com.domain {
  2.   class DebitCreditEnum {
  3.     public static const DEBIT:DebitCreditEnum = new DebitCreditEnum("debit");
  4.     public static const CREDIT:DebitCreditEnum = new DebitCreditEnum("credit");
  5.    
  6.     private static var _enumCreated:Boolean = false;
  7.  
  8.     // magic happens here, the static code block
  9.     {
  10.       _enumCreated = true;
  11.     }
  12.  
  13.     private var _name:String;
  14.  
  15.     public function DebitCreditEnum(name:String) {
  16.       if (_enumCreated)
  17.         throw new Error("The enum is already created.");
  18.       _name = name;
  19.     }
  20.   }
  21. }


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

2 Responses to “Typesafe Enum Pattern in AS3”

  1. chris Says:

    Thanks for the tip!

    I too was trying the initial approach, which led me to your post.

  2. Ciprian Says:

    I had a similar problem but I found a work-around. It’s not the nicest one, but you could instantiate your DEBIT and CREDIT in the constructor of the DebitCreditEnum class. You put them as vars, you only provide getters (to make them constant to the outside), you set them as null in the beginning, and in the constructor you test if they are null in wich case you instantiate them.

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Login