tags:

views:

261

answers:

3

Hi Could you please give me an example for Deferred execution with eager evaluation in C#?

I read from MSDN that deferred execution in LINQ can be implemented either with lazy or eager evaluation...i could find examples in the internet for Deferred execution with lazy evaluation ,however i could not find any example for Deferred execution with eager evaluation....please help me....its urgent...

Moreover,how deferred execution differs from lazy evaluation?In my point of view,both are looking same.Could you please provide any example for this too?

A: 

One way that you could eagerly evaluate a deferred execution IEnumerable is to simply turn it into an array using linq's .ToArray() function.

var evaluated = enumerable.ToArray();

This forces evaluation of the full enumerable and then you have the array that you can do whatever you want with.

Joel Martinez
Ho Joel Martinez , thanks a lot for your answer.
babu M
Not so fast! This won't work for relational data.
Peder Rice
What does relational data have to do with eagerly evaluating an ienumerable? even if the ienumerable is against something like linq2sql or ef, it will iterate all records into memory (which lets you close the db connection early).
Joel Martinez
+5  A: 

Bellow is my answer but also note that John Skeet spoke about it today on his blog an about the fact that he is not totally ok with the MSDN meaning of "Lazy" as MSDN isn't really clear of what lazy exactly mean when they use it in Just how lazy are you ? his post make for an interesting read.

Additionally Wikipedia assume that three rules should be maintained for lazy evaluation and third point isn't respected in MSDN meaning as the expression will be evaluated more than once if GetEnumerator is called again (By the spec Reset is not implemented on enumerator objects generated using the "yield" keyword and most of linq use it currently)


Considering a function

int Computation(int index)

Immediate execution :

IEnumerable<int> GetComputation(int maxIndex)
{
    var result = new List<int>(maxIndex);
    for(int i = 0; i <= maxIndex; i++)
    {
        result[i] = Computation(i);
    }
    return result;
}
  • When the function is called Computation is executed maxIndex+1 times
  • GetEnumerator return a new instance of the enumerator doing nothing more.
  • Each call to GetNext return directly the value stored in the next Array cell that List uses internally.

Deferred but eager execution :

IEnumerable<int> GetComputation(int maxIndex)
{
    var result = new List<int>(maxIndex);
    for(int i = 0; i <= maxIndex; i++)
    {
        result[i] = Computation(i);
    }
    foreach(var value in result)
    {
        yield return value;
    }
}
  • When the function is called an instance of an auto generated class (called "enumerable object" in the spec) implementing IEnumerable is created and a copy of the argument (maxIndex) is stored in it.
  • GetEnumerator return a new instance of the enumerator doing nothing more.
  • The first call to GetNext execute maxIndex+1 times the compute method, store the result in a list and return the first value
  • Each subsequent call to GetNext return a value stored in the internal Array instance of the List

Deferred and lazy execution :

IEnumerable<int> GetComputation(int maxIndex)
{
    for(int i = 0; i <= maxIndex; i++)
    {
        yield return Computation(i);
    }
}
  • When the function is called the same thing as the lazy execution case happens.
  • GetEnumerator return a new instance of the enumerator doing nothing more.
  • Each call to GetNext execute once the Compute code and let the caller immediately act on the result.

Most of linq use deferred and lazy execution but some functions can't be so like sorting.

To summarize:

  • Immediate mean that the computation/execution is done in the function and finished once the function return. (Fully eager evaluation as most C# code does)
  • Deferred/Eager mean that most of the work will be done on the first MoveNext() or when the IEnumerator instance is created (For IEnumerable it is when GetEnumerator is called)
  • Deferred/Lazy mean that the work will be done each time GetNext() is called but nothing before.

Parallel LINQ does it a little differently as the computation could be considered deferred/Lazy from the point of view of the caller but internally the computation of some number of elements begin in parallel as soon as the enumeration begin.

VirtualBlackFox
VirtualBlackFox -> thank you very much ...this is tan excellent explanation which i have never seen (atleast on this topic :) ).....but I am not still clear with your example for "deferred but eager evaluation"...,when we use yeild return keyword,it becomes lazy ...then how come you say that as "eager evaluation"..could you please explain this?moreover,how deferred execution differs from lazy evaluation?both deferred execution and lazy evaluation are same??
babu M
The description i added under each example show the difference : in this case deferred mean that the execution will be done when enumerating not when calling the function. When eager even if it happens latter all the computation will be done at the same time (when GetNext is first called) while lazy evaluation implies that each GetNext call do a part of the work.
VirtualBlackFox
The best example for the difference are "Select" and "Reverse" : Both are deferred, the source enumerable is just stored by the call to the method. Select is lazy as each time GetNext is called on the result, GetNext is called on the source, it even work with infinite sources and if a complex computation is done by the source the load will be distributed. Reverse in the other hand is eager, it need to walk the whole source enumerable before even returning it's first element, if the source is doing complex computations they will all be executed on the first GetNext call on the result.
VirtualBlackFox
A: 

VirtualBlackFox -> thank you very much ...this is tan excellent explanation which i have never seen (atleast on this topic :) ).....

but I am not still clear with your example for "deferred but eager evaluation"...,when we use yeild return keyword,it becomes lazy ...then how come you say that as "eager evaluation"..could you please explain this?

moreover,how deferred execution differs from lazy evaluation?both deferred execution and lazy evaluation are same??

Joel Martinez->Thanks a lot for your answer.

babu m
@babu when responding to others you can comment on their post so they are notified and to keep the flow of the conversation in one spot. Please add comments and delete this post. You're allowed to add comments without the minimum reputation requirement when the question is your own.
Ahmad Mageed
I added exactly what happens when each of my sample is called in my answer.Also see the John Skeet blog about it as he discuss the terms with more detail.
VirtualBlackFox