Archive for May, 2009

Creating Immutable Data Classes in C#… Quickly

Tuesday, May 26th, 2009

Of late, I’ve been tempted by F#.  In reading articles and familiarizing myself with the language, there seems to be something truly interesting there, but I just don’t grok functional programming yet.

One item in particular that I’ve seen is the Record data expression.  This allows you to create an immutable data structure, like so:

type Data = { Count : int; Name : string }
let data1 = { Count = 3; Name = "Hello"; }

Then, if at a later time you wish to change Count but keep Name the same, that’s absurdly simple.

let newData = data1 with Count = 4;

C#… does not have anything like this.  To create a similar immutable data structure (including equality checking), you’d have to do something like this:

using System;
using System.Collections.Generic;

public class Data : IEquatable<Data>
{
    private readonly int mCount;
    public int Count
    {
        get { return mCount; }
    }

    private readonly string mName;
    public string Name
    {
        get { return mName; }
    }

    public Data( int aCount, string aName )
    {
        mCount = aCount;
        mName = aName;
        return;
    }

    public Data ChangeCount( int aCount )
    {
        return new Data( aCount, mName );
    }

    public Data ChangeName( string aName )
    {
        return new Data( mCount, aName );
    }

    public bool Equals( Data aOther )
    {
        bool lResult = false;
        if ( aOther != null )
        {
            lResult = ( this.Count == aOther.Count &&
                        this.Name == aOther.Name );
        }
        return lResult;
    }

    public override bool Equals( object aOther )
    {
        bool lResult = false;
        if ( aOther is Data )
        {
            lResult = Equals( aOther as Data );
        }
        return lResult;
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }

    public static bool operator ==( Data aLeft, Data aRight )
    {
        return EqualityComparer<Data>.Default.Equals( aLeft, aRight );
    }

    public static bool operator !=( Data aLeft, Data aRight )
    {
        return !EqualityComparer<Data>.Default.Equals( aLeft, aRight );
    }
}

That’s a lot of work! In F#, what takes a single line takes 70 in C#. And a lot of that is nasty, crufty copy-paste code. And its easy to forget to change some things, like the Equals method.

Well, let me correct myself. That would be a lot of work… if I wrote that. But I didn’t. I just wrote this:

<#
this.Namespace = "Example";
this.ClassName = "Data";
this.ClassScope = "public";
this.ImplementINotifyProperty = false;
this.HashCodeVariable = "Name";
this.Variables = new List<Variable>()
{
    new Variable( "Count", "int", Options.Immutable | Options.ChangeMethod ),
    new Variable( "Name", "string", Options.Immutable | Options.ChangeMethod ),
};
#>
<#@ include file="DataClass.tt" #>

What is this mysterious mumbo-jumbo? That, sir (or madam), is T4: Microsoft’s Text Template Transformation Toolkit (aka a code generator). It is included in Visual Studio 2008, but it isn’t widely advertised.

My DataClass.tt file is a horribly messy template that takes in the values I listed above, and translates them into the real source code example I pasted above. Besides immutable data structures, it also supports mutable members, including support for INotifyPropertyChanged and [Member]Changed events.

I’m rather liking this so far. If it turns out that this code generation is a horrible idea, I can simply delete my .tt files and use my auto-generated .cs files from then-on with little loss.

Note that the following source code is not well documented, and is not very error tolerant. If you do something silly, chances are you’ll get an obtuse compilation error. I recommend modifying it to suit your own needs.

Data Class Code Generator Source Code (11 KB, requires Visual Studio 2008)

Fallout 3: The Lone Wanderer Fights for Decency

Monday, May 11th, 2009

The Lone Wanderer killed everything in the Satellite Facility.  They deserved it, after all.  With Liberty Prime… well, let’s just say Broken Steel, the Enclave deserved every laser and plasma blast.

In fact, he was in such a zeal for death and destruction that many of the crates and shelves were simply skipped past.  Upon downloading the encrypted transmission, the Lone Wanderer back-tracked and hunted for any spare ammo and other goodies.

However, fate had something different in mind.

Lo!  As the Lone Wanderer imagined himself falling down the stairwell to his death (it felt like deja vu), the Enclave had him surrounded!  He turned on V.A.T.S. and noticed… they weren’t wearing… clothes.  Well, sure, t-shirts and shorts, but their armor was missing.

Now, in addition to killing just about every good person in sight, the Enclave had now declared a war on Decency.  This could not stand.

Dude, wear some pants

Never mind me...

Let's see what kind of loot these indecent mongrels have

They... have power armor... but they're not wearing it?