Works on my machine

October 2012 Entries

Beware the IEnumerable<T>

If you see IEnumerable<T> as read only collection crippled brother, this post is for you.

Many times I found myself loosing couple of hours looking for a bug everywhere, but not in a place where it was. From time to time the bug is caused by my simplified perception of IEnumerable. The thing is, if we do not know the mechanism that serves specific IEnumerable elements, we cannot be sure that each iteration will return equal collections with same objects.

It is not a big deal if it hosts immutable objects. With mutable however, we must be careful.

Let’s analyze following properties:

public static IEnumerable<StringBuilder> ByArray
{
    get
    {
        return new StringBuilder[] { new StringBuilder("foo") };
    }
}

public static IEnumerable<StringBuilder> ByYield
{
    get
    {
        yield return new StringBuilder("foo");
    }
}

and code that operates on them:

var enumerable = ByArray;
enumerable.First()[0] = 'b';
Console.WriteLine(enumerable.First());

enumerable = ByYield;
enumerable.First()[0] = 'b';
Console.WriteLine(enumerable.First());

This will write 2 lines. Can you predict each of them ? If not, I strongly advise you to run the code.

But that is not all. Analyze those two properties:

public static IEnumerable<StringBuilder> ByDynamicArray
{
    get
    {
        return new StringBuilder[] { new StringBuilder("foo") };
    }
}

public static IEnumerable<StringBuilder> ByStaticArray
{
    get
    {
        return fooArray;
    }
}

private static StringBuilder[] fooArray =
    new StringBuilder[] { new StringBuilder("foo") };

and their usage:

ByDynamicArray.First()[0] = 'b';
Console.WriteLine(ByDynamicArray.First());

ByStaticArray.First()[0] = 'b';
Console.WriteLine(ByStaticArray.First());

Notice that now we are operating directly on property, not on a local variable like in previous example. This is also important and can cause different output.

So be careful and think twice before writing code that operates on IEnumerable<T>.

Linq’s ZIP for adjacent items

I found that Linq’s ZIP is really great for adjacent item computations.

For example, let’s have a collection of dates:

var dates = new DateTime[]
{
    new DateTime(2000,1,1),
    new DateTime(2000,1,2),
    new DateTime(2000,1,5)
};

How would you compute time difference of adjacent items ?

I like to use Zip for this kind of job:

dates.Zip(dates.Skip(1), (d1, d2) => d2 - d1);

As you might expect, the result will be: { 1 day, 3 days }