November 2009 - Posts

It’s Beta For a Reason!

Today, I was in the process of creating a branch of Elevate to support .NET 4.0 when I came across a subtle, but breaking change in the Enumerable.Count function. The following code works in .NET 3.5, but fails in .NET 4.0 Beta 2:

[TestClass]
public class CountBug
{
    public class MyIList : IList<int>
    {
        public MyIList()
        {
            GetEnumeratorWasCalled = false;
            CountWasCalled = false;
        }
        
        //...non-relavent IList members excluded for this post...
        
        public bool GetEnumeratorWasCalled { get; set; }
 
        public IEnumerator<int> GetEnumerator()
        {
            GetEnumeratorWasCalled = true;
            return null;
        }
 
        public bool CountWasCalled { get; set; }
 
        public int Count
        {
            get
            {
                CountWasCalled = true;
                return 0;
            }
        }
    }
 
    [TestMethod]
    public void CountBehavior()
    {
        var list = new MyIList();
        Assert.AreEqual(0, list.Count());
        Assert.IsTrue(list.CountWasCalled);
        Assert.IsFalse(list.GetEnumeratorWasCalled);
    }
}

 

The Enumerable.Count method in .NET 4.0 Beta 2 fails to recognize that MyIList implements ICollection<T>, so instead of returning the .Count property, it calls the MyIList’s GetEnumerator() method and walks every item in the list to determine the count. In .NET 3.5, MyIList is identified as an ICollection<T> implementer and the .Count property is correctly used.

It’s also worth noting that it does not seem to be possible to create a MSTest test project in Visual Studio 2010 Beta 2 that targets .NET 3.5. It will silently upgrade any of your .NET 3.5 test projects to .NET 4.0 even if you select 3.5 as the target framework when creating a project!

I’ve filed the following bugs on connect, so hopefully they get resolved soon!

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=514122

[update: I initially posted a link to the wrong bug. The above link has been corrected.]

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=514130

Designing F# Functions for Currying and the |> Operator

Last week, I led a jam about F# at the Ann Arbor Study Group. One of my SRT Solutions coworkers, Ben Barefield, asked a question that warrants further discussion. After I introduced the forward pipe (|>) operator, Ben asked the following:

In F# programming, do you design functions so the last argument is one that you intend for users to pass via the forward pipe operator?

My first response was a tentative “yes”, but I felt like that put too much focus on the forward pipe operator. After some reflection, I think a better answer is to follow this more general best practice:

In F# programming, prefer ordering function arguments from least varying to most varying.

Normally, you’ll see this discussed in the context of currying and partial application, but I think that it is equally important when considering the forward pipe operator. Let’s take a look at some examples of each.

Currying and Partial Application

We’ll start with the Seq.reduce function. The signature for this function is:

Seq.reduce : ('T -> 'T -> 'T) -> seq<'T> -> 'T

The F# documentation states that reduce is used to “Apply a function to each element of the sequence, threading an accumulator argument through the computation.” In practice, reduce is used to compute a single value from a sequence of values. For example:

> Seq.reduce (+) {0..5};;
val it : int = 15

Here, the computation starts with the first two elements of the sequence, 0 and 1. Reduce applies the addition function to these elements to return 1. This is now our current “state” which we carry over into the next step of computation. Reduce will grab the next element in the list, 2, and call our addition function with that argument and our current state of 1 to produce 3. This process continues until we get our result of 15.

Now that we know how reduce works, observe that the arguments are structured from least varying to most varying. When viewed from the standpoint of currying this is handy because it allows us to create useful residual functions through partial application:

> let mySum<'a> = Seq.reduce (+);;

val mySum<'a> : (seq<int> -> int)

> mySum {0..5};;
val it : int = 15

The |> Operator

In F#, it’s common to rewrite the first example from above using the forward pipe operator:

> {0..5}
   |> Seq.reduce (+);;
val it : int = 15

This compatibility with the forward pipe operator also comes naturally as a result of ordering arguments from least varying to most varying. Because the last argument is the one that is most likely to vary, it follows that it is also the argument that we are most likely to pass via the forward pipe operator.