Partilhar via


Deferred Execution

[Blog Map]  [Table of Contents]  [Next Topic]

Deferred execution is a topic related to lazy evaluation, but it is a topic worth discussing in its own right.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCIn the previous topic, we saw this code as an example of lazy evaluation:

using System;
using System.Collections.Generic;
using System.Linq;

public static class MyExtension
{
public static IEnumerable<string> ToUpper(this IEnumerable<string> source)
{
foreach (string s in source)
{
Console.WriteLine("Yield returning: {0}", s);
yield return s.ToUpper();
}
}
}

class Program
{
static void Main(string[] args)
{
string[] sa = new[] {
"aaa",
"Bbb",
"CCc"
};

Console.WriteLine("Before using ToUpper()");
var sb = sa.ToUpper();

Console.WriteLine("After using ToUpper()");
Console.WriteLine("Before iterating the collection in sb");

foreach (string s in sb)
Console.WriteLine("Within iteration, s: {0}", s);

}
}

It produces the following output:

Before using ToUpper()
After using ToUpper()
Before iterating the collection in sb
Yield returning: aaa
Within iteration, s: AAA
Yield returning: Bbb
Within iteration, s: BBB
Yield returning: CCc
Within iteration, s: CCC

In addition to lazy evaluation, the above code also demonstrates deferred execution.  The program doesn't even start to iterate over the source array until it iterates over the result collection.

Contrast that program to this:

using System;
using System.Collections.Generic;
using System.Linq;

public static class MyExtension
{
public static IEnumerable<string> ToUpper(this IEnumerable<string> source)
{
List<string> result = new List<string>();
foreach (string s in source)
{
Console.WriteLine("Adding {0} to list", s);
result.Add(s);
}
return result;
}
}

class Program
{
static void Main(string[] args)
{
string[] sa = new[] {
"aaa",
"Bbb",
"CCc"
};

Console.WriteLine("Before using ToUpper()");
var sb = sa.ToUpper();

Console.WriteLine("After using ToUpper()");
Console.WriteLine("Before iterating the collection in sb");

foreach (string s in sb)
Console.WriteLine("Within iteration, s: {0}", s);

}
}

This program creates the result set in a List<string> just as soon as ToUpper is executed.  This is an example that exhibits non-deferred execution.  You have probably written code similar to this many, many times.  And, of course, it produces this output:

Before using ToUpper()
Adding aaa to list
Adding Bbb to list
Adding CCc to list
After using ToUpper()
Before iterating the collection in sb
Within iteration, s: aaa
Within iteration, s: Bbb
Within iteration, s: CCc

In the previous topic, we also saw an example that used deferred execution and eager evaluation.  There are a number of standard query operators that behave in this fashion, such as OrderBy.  Of course, the only possible implementation of OrderBy is to iterate over the source, sort it, and then finally yield the first item in the result collection.  There is no other way to do it.

So, you can have deferred execution and lazy evaluation or deferred execution and eager evaluation.  Non-deferred execution is always eager.

Most of the standard query operators use deferred execution.  Some of them implement lazy evaluation. In addition, most of the LINQ to XML axis methods use deferred execution and lazy evaluation.

[Blog Map]  [Table of Contents]  [Next Topic]

Comments

  • Anonymous
    June 18, 2008
    PingBack from http://blogs.msdn.com/ericwhite/pages/FP-Tutorial.aspx

  • Anonymous
    July 24, 2008
    One small observation - in the second example, the 'ToUpper()' function is a confusing name to use because it does not appear to actually perform this functionality on the string (although it did in the first example). Fantastic tutorial!