Archive for the ‘enum’ Category
Faking Enums in AS3
[Update: the final version of my enum class is here.]
Just a little quickie. I happen to be working in Flex (which I love) and I came up with what I think is the best way to fake enums in AS3. It’s a distillation of the best I found through Google and adding my own little goodie to help debugging. It goes something like this:
class EState { public var Text :String; {CStringUtils.InitEnumConstants(EState);} // static ctor public static const Initializing :EState = new EState(); public static const Connecting :EState = new EState(); public static const Loading :EState = new EState(); public static const Ready :EState = new EState(); }
It requires a function to set it up:
class CStringUtils { public static function InitEnumConstants(inType :*) :void { var type :XML = flash.utils.describeType(inType); for each (var constant :XML in type.constant) inType[constant.@name].Text = constant.@name; } }
The class “EState” above is the basic pattern I follow for all my enums. Make it a class, add a Text field, a bit of static ctor code, and then one simple line for each constant.
There are a thousand examples of how to do fake enums in AS3 on Google, but they suffer from two key flaws.
Type safety
The simplest way to fake enums in AS3 is to use an int or a string and have constants that represent each of the enum members. This isn’t type safe, not to mention is lousy for usability (code completion totally fails here). With the above method, a function receiving an EState enum can only receive an EState, which will be one of the static constants such as EState.Initializing.
Debuggability
Most of the good fake enum examples online do what I have above – a class with static const members that represent each member. The big problem is that you can’t debug these at all. If you are inspecting a class with a member var of type EState you have to also look at all the static consts of EState to compare the internal address against to find out what you’re looking at. Way better is to include in the enum constant itself its own name.
Here’s a shot of Flex’s watch window. Normally you’d only see the @46fa341, but with the “Text” string member you can expand it to see what the variable is really set to.
I saw a couple examples of this online where you’d pass in the name in the enum’s ctor, but why not automate it? That’s where the CStringUtils.InitEnumConstants comes in. For each enum class, add some static ctor code that just calls InitEnumConstants on the type. This uses reflection to initialize the names of every constant in the “enum”. Now there is exactly one place to put the name of each enum constant and it looks a lot cleaner.
Extensibility
A lot of the time you want more than just the name to be embedded in the enum constants. Perhaps a description field, or anything else that adds metadata to the constant (I wrote a bit about this earlier). No problem, just add new fields to the class, and then a ctor that receives them. Pass in the metadata initializers into the ctor as each constant is constructed.
Adding Attributes to Enums: Background
I’m finally getting back to the enum series.
What I mean by “Attributes”
I’m using “attribute” in the modern language sense – metadata that you can attach to a symbol. C# got it dead right with their implementation. In C#, attributes can be attached to types, function parameters, constants, methods, just about anything. Then you can query them back fairly cheaply to do operations based on them from within the game or a tool. The XML serialization system uses this pretty heavily to let you customize how a class gets serialized to/from XML. Attributes are used all over the .NET runtime to do interesting and useful things. Wouldn’t it be nice to get the same from C++?
In C++ it’s not directly supported by the language, but we can fake it with macros, templates, or compile-time tools, or some combination. Any game that has any form of run-time typing information probably uses something like a DECLARE_RUNTIME_CLASS( classname ) to build tables about class inheritance and members. We could do something similar to declare file-scope statics that tack metadata onto whatever we like.
For this series, I’m limiting my scope to just enum constants. Why? Because they’re a pain to attribute. When you’re inside of an enum declaring constants, the only thing you can put in there is constants. So if you have a constant and you want a string equivalent to it or attach other metadata to it, you must wait until the end of the enum definition to do that. The more constants in the enum, the further away your metadata gets from what it is describing, and the easier it is to get out of sync or introduce subtle errors. Not to mention loss of readability.
Quick detour
Before I go into this, I need to switch examples. The EGame enum from my previous posts is too contrived. Let’s choose a much more practical example, one from my past: bytecodes for the virtual machine of a roll-your-own scripting language. I’ve written several of these, but I definitely don’t recommend writing a scripting language today. Just use or adapt Lua.
Let’s use this simplified enum:
enum Op { OP_ADD, OP_SUBTRACT, OP_MULTIPLY, OP_DIVIDE, OP_ISEQUAL, OP_ISGREATER, OP_LOAD, OP_STORE, OP_POP, OP_PUSH, OP_SWAP, };
Pretty straightforward. Some operations to do a little math, comparisons, and variable/stack manipulation. A real Op enum would have many more opcodes. The Skrit language I wrote for Dungeon Siege had perhaps 60 and Sheep from Gabriel Knight 3 had around 40. Lua 5.1 has 38. The size matters. If we only had 5-10 items in our enum, it probably wouldn’t be worth doing all this mess I’m about to talk about.
Attributes we need
For each of these opcodes, we’re interested in knowing several things:
- The binary representation
- The Op enum constant is usually the opcode itself. Usually this means casting it to the native instruction size of your VM, most often a byte.
- With more complicated op schemes that have variable-length instructions, the most famous example being x86 assembly, there may be some processing required just to figure out the size of the op. This makes compiler and VM construction a lot more complicated. It also may stand in the way of a simple set of lookup tables to attach attributes to opcodes. If the possible set of opcodes is huge due to the number of combinations of prefixes and micro-ops, then the table-based approach I’m going for in this series is probably not going to work. An algorithmic or perhaps a combined algorithm/table approach would be required.
- A string representation of the opcode
- This is important for printing out error messages or for dumping a disassembly of the compiled source. So OP_ADD becomes “OP_ADD”. And in our VM’s error handler we can do a mixed-mode disassembly with the aid of a ToString():
printf("%04X %02X %s\n", offset, op, ToString(op) );
- We may also want to have a more human readable description if we’re generating low-level help automatically. So OP_ADD would need “Pop top two stack items and push the sum”. Lua for example just embeds this as a comment. For example, here’s their OP_ADD, as well as a more complicated op that I copy-pasted from lopcodes.h:
- The size of the trailing data
- Lots of things are easier if you can easily ask how big the entire op + its data is, like disassembly, or patching the bytecode at runtime to make breakpoints, etc. OP_ADD will require different data from OP_RETURN, for example.
- Flags regarding each op’s behavior
- Perhaps your VM is statically typed and the type info is lost at compile time. You may require different OP_ADD variants for integer vs. float vs. string data – Skrit had OP_ADDI, OP_ADDF, and OP_ADDS. If this is the case, it would be convenient to attach flags to your ops to say what type of data the op works on.
- As a practical example, in Skrit, when I was compiling a two-data operation like + or || I would call a general emit function that could determine if conversions were required by either side based on traits attached to the op. If TRAIT_LOGIC was set I’d only permit ints and bools as the data. For TRAIT_MATH opcodes I’d check both sides to see if they were compatible and emit promotions for one or the other if not. It was convenient to be able to tell if a proposed op was string-compatible by checking TRAIT_STRING.
OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
So for a given enum constant, we want to be able to gather each of these attributes, and quickly. Next article I’ll go into the implementation details.
Enumerating the enum
The first thing I wanted to do was have the ability to enumerate the constants. I can think of a couple reasons we’d want to do this:
- You want to get a list of all available enum constants to store somewhere, perhaps a developer UI. For example, your Maya plugin has a property grid that lets you change the startup state of an object. The available constants can be turned into a dropdown box. Note that this requires attributes so you can get the string form of the constant (see next article in this series).
- You want to do processing sensitive to each constant. Say you have a database mapping stages of your game object sim pipeline to callbacks – EState_PreWorldUpdate, EState_PreWorldRender, etc. If the enum constants are in priority order, you can just iterate through them all, indexing into your database by int (the db can just be an ordinary array) to hit the callbacks.
The key advantage to being able to enumerate the enum is that you can add and rearrange your enum constants however you like and you don’t need to update the loops that iterate over them. Of course, the old rules still apply about storing enums in a file in binary form – if you change what the enum means, you’re changing the schema, and you’re going to have to migrate those changes using a tool of some kind. My preferred way to do this is by storing in string form, but that’s a topic for a later day.
Here’s the macros I use to make this happen:
#define BEGIN_ENUM( inPrefix, inStart ) \ inPrefix##Begin = inStart, \ inPrefix##BeforeBegin = inStart - 1 \ #define END_ENUM( x ) \ inPrefix##End, \ inPrefix##Count = inPrefix##End - inPrefix##Begin
And example usage:
enum EGame
{
EGame_Invalid,
BEGIN_ENUM( EGame_, 1 )
EGame_LodeRunner,
EGame_DonkeyKong,
EGame_BioShock,
EGame_DungeonSiege,
EGame_StarControl2,
END_ENUM( EGame_ ),
};
The usage pattern is to surround your enum constants with the pair of macros. Most of the time that ‘1′ will be a ‘0′ but in this case, I wanted the 0 to mean ‘invalid’ and not to be considered part of the active array. If you want to use -1 for invalid, then put a = -1 after your invalid constant and start out your BEGIN_ENUM at 0.
Now we have three key new constants: EGame_Begin, EGame_End, and EGame_Count. The count is accurate regardless of the starting index of the enum, which is an advantage over the typical trick of adding an extra enum at the end such as EGame_Max.
Begin and End are used for the actual iterating, and I like using STL concepts so End is one past the end. Before we can do the iterating though, we need another macro. Enums are not always treated as integers (which is a good thing) so we need to define operators to let us do some basic math on them. Because the same set of operators is always needed when doing iteration like this, let’s wrap it up in a macro to keep the noise level down:
#define MAKE_ENUM_MATH_OPERATORS( inType ) \
inline inType operator ++( inType& ioA ) \
{ return ioA = (inType)(ioA + 1); } \
inline inType operator ++( inType& ioA, int ) \
{ inType old = ioA; ++ioA; return old; } \
inline inType operator --( inType& ioA ) \
{ return ioA = (inType)(ioA - 1); } \
inline inType operator --( inType& ioA, int ) \
{ inType old = ioA; --ioA; return old; } \
inline inType operator +( inType inA, inType inB ) \
{ return (inType)((int)inA + (int)inB); } \
inline inType operator -( inType inA, inType inB ) \
{ return (inType)((int)inA - (int)inB); } \
inline inType operator +=( inType& ioA, inType inB ) \
{ return ioA = (inType)(ioA + inB); } \
inline inType operator -=( inType& ioA, inType inB ) \
{ return ioA = (inType)(ioA - inB); }
Now, we can finally do the iteration:
MAKE_ENUM_MATH_OPERATORS( EGame );
for ( EGame i = EGame_Begin ; i != EGame_End ; ++i )
{
printf( "%d", i );
}
Again, this is of much more value as we add attributes to the enum constants. Then we can build tables of enums and associated attributes. Enums are fast and compile-time checked, much better than simple int indexes. I’ll go into a sample usage in the next article that should show why this is so useful. Every game frequently has this need!
One important note: this system assumes a continuous set of integers. If there is a “step” in the series, or if you use “bitwise” enums, it can’t work. It’s meant for when you let the compiler assign constants and don’t do it yourself.

