Wednesday, April 14, 2010

C# - Extension methods

"Extension methods should be able to modify instance values"

I recently set out to create a library for bit manipulation in C#. Specifically to add these capabilities as naturally as possible to the ulong datatype (used a lot in chess programming ;-). What I envisioned was this;

public static void SetBit(this ref ulong data, byte bitIndex)
{
 data = data | ((ulong)1 << bitIndex);
}

This enables code to be used like this;

ulong BitBoard;


BitBoard.IsBitSet(22); 
BitBoard.SetBit(22); 


Directly changing the value of the BitBoard ulong variable. And ofcourse appear in the methods list intellisensed on ulong variables (if the right namespace was being used). Unfortunately the this modifier (making it an extension method) prohibits the use of ref and out, breaking the above code.

There is no way to do this in C# that I found. It is possible in .NET because another .NET language named Visual *ouch* Basic allows ref combined with this in extension methods. So what options do I get in my favorite language;

BitBoard = Bitboard.SetBit(22);// Extension method, intellisensed
SetBit(ref BitBoard,22);       // public static call
BitBoard.SetBit(BitBoard,22);  // Extension method using extra ref parameter 
                               //  (ugly as ####)
BitBoard.SetBit(22);           // Wrap the ulong in a struct

All of them are ofcourse vastly inferior from a beatiful and clean code point of view. The second method using a ref parameter will probably be fastest, although creating a struct with only a ulong var inside also comes a long way in achieving nice, clean coding. After some tests the struct wrapping turns out to be just as fast as using regular calls with a ref parameter. Only disadvantage is that you need the value inside the struct for normal operations. So you would need to write BitBoard.Value * 5 for normal pre-existing operations a ulong can participate in. Value would be the public ulong that's the structs only data. This would have been BitBoard * 5 with the extension method approach.


Before you ask, these are the alternatives available in Framework #4 for bitwise programming;

- BitVector32 exists (valuetype, but exists only as a 32 bits uint)
- BigInteger (large, slow immutable reference type)
- BitArray (reference type)

All of them are missing bitwise routines I would like to use. And I want my type to be a valuetype for performance and minimal storage reasons.