Exploring our Lazy Class

We’ll dive in by writing an generic class that represents the delayed (and lazy) computation, Lazy<T>.  Actually it is just a class that will execute a piece of code once somebody asks for the a result. It will also need to cache this result, so that we can enforce that the code is at most executed once. It is pretty easy to represent this in C#: for the ‘piece of code’ that we need to execute, we can use aFunc delegate. We’ll also use generics, since this ‘piece of code’ can return any .NET type.

public class Lazy<T>
{
    private Func<T> func;
    private T result;
    private bool hasValue;

    public Lazy(Func<T> func)
    {

        this.func = func;
        this.hasValue = false;
    }
    public T Value
    {
        get
        {
            if (!this.hasValue)
            {
                this.result = this.func();
                this.hasValue = true;
            }
            return this.result;
        }
    }
}

Our new class had three fields; we have our func field, a delegate that will be executed when someone tries to access the value. The hasValue field is a Boolean saying whether we already called our delegate. Finally, our result field stores the result after the delegate was called. The only logic of the class is in our Value property, which returns the value calculated by the delegate. The getter first tests if we already have our result and decides whether the delegate should be executed or not. In either case we can return the result that was calculated earlier (either previously or just before).
Wouldn't it be fun if we could actually use this class as well? Let’s find out how we can do that. Our constructor expects a value of type Func<T>, this represent a delegate that doesn’t have any arguments and returns a value of the type T. The main advantage of using this type is that we can use an anonymous function to write our code that will be executed in a very compact way directly when getting the value of our Lazy<T>. In our first example we will create a lazy value that first prints a string to the console window and then returns an numeric value once it is executed. Now we can trace when the Lazy<T> is executed.

Lazy<int> lazy = new Lazy<int>(() =>
{
    /* This should take a while */
    Console.WriteLine("Working on it...");
    return 42;
});

Console.WriteLine("What is the answer to the ultimate question of life,
                                the universe, and everything?");

Console.WriteLine("The answer is {0}", lazy.Value);           /* First try */
Console.WriteLine("The answer is (again) {0}", lazy.Value);   /* Second try */

In our sample we first create a variable called lazy. This variable represents our lazy value. We print a string to the console and then use the Value property of our lazy value to get the result from our computation (even twice!). 

Taking it to the next level (with C# Type Inference)

Before we move on to more interesting (and more useful) examples, we’ll try to improve our Lazy<T> class. Our syntax that we currently use for creating our lazy value is somewhat too verbose since we have to write Lazy<int> twice.  Fortunately we can simplify this using C# type inference. Because of this it’s possible to omit the type arguments when calling a generic method. To use this technique we write a simple static helper class with a static method for creating a lazy value.

public static class Lazy
{
    public static Lazy<T> New<T>(Func<T> func)
    {
        return new Lazy<T>(func);
    }
}

When using this static class, we can easily create a lazy value by calling Lazy.New() instead of writing new Lazy<int>.  When we combine this with the var keyword in C# (which tells the compiler to infer the type of the variable automatically depending on the expression used to initialize the variable) we get an even more compact syntax. In addition this helper class gives you the ability to use anonymous types as well. This can often be useful, as demonstrated in the following example where we’ll use this to create a lazy type representing both the sum and the product of two numbers.

int a = 22, b = 20;

var lazy = Lazy.New(() =>
{
    Console.WriteLine("Calculating...");
    return new { Prod = a * b, Sum = a + b };
});

Console.WriteLine("The product is {0} and the sum is {1}", lazy.Value.Prod, lazy.Value.Sum);
What about a lazy value as an argument of a method?

As mentioned in the introduction, one of the aspects of eager evaluation is that the arguments of a method are evaluated before the method is actually called. This may not be the best thing to do if calculations could take a long time to process or if the result may even not be necessary. On the other side, when talking about lazy evaluation, the arguments are never evaluated unless the value is actually required in the method body. We can simulate this behavior using our lazy values. In our example we’ll take two lazy values and end up using only one of them.

static Random rnd = new Random();
static void UseRandomArgument(Lazy<int> a0, Lazy<int> a1)
{
    int res;
    if (rnd.Next(2) == 0)
        res = a0.Value;
    else
        res = a1.Value;

    Console.WriteLine("Our result is {0}", res);
}

In order to call this method we will need to create two lazy values (using our Lazy.new method). To show how this code behaves we’ll add a call to Console.WriteLine in every anonymous function.

var calc1 = Lazy.New(() =>
{
    Console.WriteLine("Calculating #1"); return 42;
});

var calc2 = Lazy.New(() =>
{
    Console.WriteLine("Calculating #2"); return 44;
});

UseRandomArgument(calc1, calc2);
UseRandomArgument(calc1, calc2);

When you execute this code you’ll experience different behavior on each run. Depending on the run only the first, only the second or both the lazy arguments are calculated. It is important (and easy) to notice here that not each argument is always executed. 

Comments

Popular posts from this blog

Hosting WCF in IIS(9 Steps)

Difference between IEnumerator and IEnumerable

MVC and MVVM Architecture