HashPasswordForStoringInConfigFile and Either in C#

Posted by Amos Robinson on February 14th, 2008 filed in , ,

I think KeyValuePair is a bad class name, for similar reasons that I think (and everybody knows) that HashPasswordForStoringInConfigFile is bad.
It’s not really a problem that the latter is insanely hard to type. It’s annoying, yes, but in most cases code completion dismisses that complaint. The real problem is that you’re assuming too much about your caller. If you look at the Google search for HashPasswordForStoringInConfigFile, you’ll notice that the first two results only mention that “you can store this value in a config file” and the third doesn’t mention config files at all - its return value is stored in a database instead.
The same reasoning, then, is easily applied to KeyValuePair: the only part of its interface that implies it should be used for key/value pairs are themselves arbitrary names - so they’re really just un-glorified pairs, with bad field names.
This problem manifests itself in many other ways than just names, though; take for instance, the Nullable<T> type. If you’re familiar with Haskell, you would know about the Either a b data type. Suppose that we felt the need to implement this in C#, a naive implementation would be something like:

class Either<L,R>
{
    readonly L left;
    readonly R right;
    public Either(L left_) { left = left_; }
    public Either(R right_) { right = right_; }

    public bool IsLeft { get { return left != null; } }
    public L Left {
        get {
            if (left == null)
                throw new NullReferenceException("Either is not a left-value");
            return left;
        }
    }

    public bool IsRight { get { return right != null; } }
    public R Right {
        get {
            if (right == null)
                throw new NullReferenceException("Either is not a right-value");
            return right;
        }
    }

    // and so on

}

There are problems with this. Mainly, that it won’t compile. In its current state, we’ll need to add an extra constraint onto our class so that it only works with reference types - which isn’t what we want. Ideally here, we would simply be able to change readonly L left; to be readonly L? left;, tweak the accessor methods slightly, and be done with it. However, L? in turn requires that types be non-nullable value types. So then we’re limiting ourselves to value types, which isn’t ideal either.
The solution, then, turns out to be as simple as adding field - a flag:

class Either<L,R>
{
    readonly bool isLeft;
    readonly L left;
    readonly R right;

    public Either(L left_) {
        left = left_;
        isLeft = true;
    }

    public Either(R right_) {
        right = right_;
        isLeft = false;
    }

    public bool IsLeft { get { return isLeft; } }
    public L Left {
        get {
            if (!IsLeft)
                throw new NullReferenceException("Either is not a left-value");
            return left;
        }
    }

    // and so on

}

And this also gives us another win that our first (reference only) implementation didn’t allow us: we can now store null values of either type inside.

Leave a Comment