Minor update to Enum size guideline

Here is a minor clarification on the enum size guidelines.  Please let me know if you have any questions or comments.  

As always, you can check out the base design guidelines and my incremental updates.

Do use Int32 (the default in most programming languages) as the underlying type of an enum unless any of the following is true:

1. The enum represents flags, and you expect many flags (>32) now or in the future.

Annotation (BradA):  This may not be as uncommon a concern as you might first expect.  We are only in V2.0 of the .NET Framework and we are already running out of values in the CodeDom GeneratorSupport enum.  In retrospect, we should have used a different mechanism for communicating support of a larger underlying type.

2. The type needs to be different than Int32 for backward compatibility.

3. You expect to it to be common to create a hundred or more instances of the enum by using the enum as a field in a frequently instantiated structure or class; storing many instances in arrays, files, etc.  In such cases smaller is better.  If you expect to the enum to be used mostly as a singleton for flow of control the size makes little differences.   

Annotation (BradA): Note that for in memory usage you should be aware that managed objects are always DWORD aligned so you effectively need multiple enums or other small structures in an instance to pack a smaller enum with to make a difference as the total instance size is always going to be rounded up to a DWORD.


Annotation (BradA): Keep in mind it is a binary breaking change to change the size of the enum type once you have shipped, so chose wisely, with an eye on the future.  Our experience is that Int32 is usually the right choice and thus we made it the default.  


Comments (6)

  1. Frank Hileman says:

    Thanks for fixing that. Small enums can make a difference when packing things tightly. C# will pack any combo of 4 byte-sized enums or booleans into a single 32-bit word within a single struct or class.

    One other thing I would like to see addressed: writable properties on structs. I believe this is against the guidelines right now?

    This is related to building tight data structures. Often I have compressed a bunch of booleans and enums into one or two 32-bit uints with bitflags. To make it user-friendly, I wrap the whole thing in a struct. This works great in C#. That way I get or set properties on the struct, and the struct encapsulates all the bit-fiddling.

    However this technique is not useful without writable properties on the struct. In fact, anytime you need to modify a single piece of data in a struct, that encapsulates several pieces of data, it is much more convenient to use a writable property, instead of recreating the struct with another constructor.

  2. Josh Williams [MS] says:

    It is worth noting that on Whidbey 64bit platforms managed objects will be QWORD (or 8-byte) aligned and there are penalties and benefits that follow with that.

  3. Frank Hileman says:

    Josh, I can see the penalties pretty clearly. The benefit, I suppose, is speed on the 64-bit processor?

  4. Josh Williams [MS] says:

    Speed definetly, and unfortunately correctness. If you use a native debugger and look at a reference class in memory you will find that the first thing there is a pointer to a MethodTable for the object, and that pointer needs to be pointer size aligned or else on platforms like IA64 we will have to be _very_ careful (and slow) or we end up with a data misaligned exception getting thrown by the hardware. In the 64bit case that means we need 8-byte alignment.

  5. Frank Hileman says:

    Sorry to continue the thread here, but will structs in arrays also be 8-byte aligned? This would be a shame.

  6. Josh Williams [MS] says:

    Nope. Structs in arrays continue to be aligned as per their required natural alignment requirements, so you will still get efficent packing of managed structs.

    I should qualify my above note, objects in the managed heap are forced to pointer sized alignment (4byte on x86, 8-byte on x64/IA64). Managed structs which are created on the stack are not and will instead be aligned as per thier individual alignment requirements. This holds for structs in arrays.

    There are stack usage penalties to moving to 64bit platforms (larger return address pushed on the stack, larger argument space [each slot is bigger], larger amt of space taken to save out scratch registers and such), but unless you’re doing something highly recursive or otherwise near the limit it shouldn’t be overly devastating. Luckily, forcing alignment of managed structs created on the stack isn’t one of those penalties.

    Sorry if I misled.