Wednesday, August 1, 2012

Use components that uses yield return

When to use yield return?

You were given a task to shop for a component you cannot make by yourself, say fibonacci number generators.

You found two vendors. Both of their components produces correct output, both of them can generate up to fifty fibonaccis, and both of them are priced the same.

All things being equal, you are left with one qualifier, a good qualifier, you want to choose the component with a better quality. But for some reasons, these two vendors don't want to give you their source codes, hence you cannot see how they implement things. They just want to give you the DLL only.

But those vendors still have some kindness left in their hearts, they at least give you a clue how their components work.

Vendor A told you they uses eager loading(i.e. uses IList)
Vendor B told you they uses lazy loading(i.e. uses yield return)

In case like this, you need to purchase vendor B's component.

Vendor A's approach uses too much memory, they put elements to an allocated memory. Vendor B generates elements on-the-fly.


Desirability of vendor B's approach is more apparent if for example you just want the 8th fibonacci.

Using vendor A's component, your code still need to wait a long time in order to get the 8th element. Why it is so? Even you just want the 8th element, your code still need for vendor A's component to generate the whole 50 elements, after doing so, then that's the only time you can pick the 8th element.


Using vendor B's component, if you just want to get the 8th element, it will stop generating on the 8th element. Your code don't need vendor B's component to generate all the 50 elements in order for your code to get the 8th element. Vendor B's component has some smart on it.


To contrast the difference between IList and yield return, check the output of this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ChooseLesserOfTheTwoEvils
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoopOnEvilA();
            Console.WriteLine("------");
            TestLoopOnEvilB();
            Console.WriteLine("------");
 
            Console.ReadKey();
             
            TestPick8thOnEvilA();
            Console.WriteLine("------");
            TestPick8thOnEvilB();
            Console.WriteLine("------");
 
            Console.ReadKey();
        }
 
        static void TestPick8thOnEvilA()
        {
            Console.WriteLine("TestPick8thOnEvilA");
            long eighth = EvilCompanyA.MathProvider.Fibonacci().Skip(7).Take(1).Single();
            Console.WriteLine("\nEvil A's 8th fibonacci is {0}", eighth);
        }
 
        static void TestPick8thOnEvilB()
        {
            Console.WriteLine("TestPick8thOnEvilB");
            long eighth = EvilCompanyB.MathProvider.Fibonacci().Skip(7).Take(1).Single();
            Console.WriteLine("\nEvil B's 8th fibonacci is {0}", eighth);
        }
 
        static void TestLoopOnEvilA()
        {
            Console.WriteLine("Test Loop On Evil A");
            IEnumerable<long> bucket = EvilCompanyA.MathProvider.Fibonacci();
            Console.WriteLine("\nTest start");
 
            foreach (var item in bucket)
            {
                Console.WriteLine("Evil A's Fib: {0}", item);
            }
            Console.ReadLine();
        }
 
         
        static void TestLoopOnEvilB()
        {
            Console.WriteLine("Test Loop On Evil B");
            IEnumerable<long> bucket = EvilCompanyB.MathProvider.Fibonacci();
            Console.WriteLine("\nTest start");
 
            foreach (var item in bucket)
            {               
                Console.WriteLine("Evil B's Fib: {0}", item);
            }
            Console.ReadLine();
        }
    }
 
     
}
 
 
namespace EvilCompanyA
{
    public static class MathProvider
    {
        public static IEnumerable<long> Fibonacci()
        {           
            IList<long> il = new List<long>();
 
            long a = 0, b = 1;
 
            for (int i = 1; i <= 50; ++i)
            {
                Console.Write("eager{0} ",i);
                il.Add(a);
                long n = a;
                a += b;
                b = n;
            }
                   
 
             
            return il;
        }
    }
}
 
namespace EvilCompanyB
{
    public static class MathProvider
    {
        public static IEnumerable<long> Fibonacci()
        {
            long a = 0, b = 1;
 
            for (int i = 1; i <= 50; ++i)
            {
                Console.Write("lazy{0} ",i);
                yield return a;
                long n = a;
                a += b;
                b = n;
            }
        }
    }
}

Output:

Test Loop On Evil A
eager1 eager2 eager3 eager4 eager5 eager6 eager7 eager8 eager9 eager10 eager11 eager12 eager13 eager14 eager15 eager16 eager17 eager18 eager19 eager20 eager21 eager22 eager23 eager24 eager25 eager26 eager27 eager28 eager29 eager30 eager31 eager32 eager33 eager34 eager35 eager36 eager37 eager38 eager39 eager40 eager41 eager42 eager43 eager44 eager45 eager46 eager47 eager48 eager49 eager50 
Test start
Evil A's Fib: 0
Evil A's Fib: 1
Evil A's Fib: 1
Evil A's Fib: 2
Evil A's Fib: 3
Evil A's Fib: 5
Evil A's Fib: 8
Evil A's Fib: 13
Evil A's Fib: 21
Evil A's Fib: 34
Evil A's Fib: 55
Evil A's Fib: 89
Evil A's Fib: 144
Evil A's Fib: 233
Evil A's Fib: 377
Evil A's Fib: 610
Evil A's Fib: 987
Evil A's Fib: 1597
Evil A's Fib: 2584
Evil A's Fib: 4181
Evil A's Fib: 6765
Evil A's Fib: 10946
Evil A's Fib: 17711
Evil A's Fib: 28657
Evil A's Fib: 46368
Evil A's Fib: 75025
Evil A's Fib: 121393
Evil A's Fib: 196418
Evil A's Fib: 317811
Evil A's Fib: 514229
Evil A's Fib: 832040
Evil A's Fib: 1346269
Evil A's Fib: 2178309
Evil A's Fib: 3524578
Evil A's Fib: 5702887
Evil A's Fib: 9227465
Evil A's Fib: 14930352
Evil A's Fib: 24157817
Evil A's Fib: 39088169
Evil A's Fib: 63245986
Evil A's Fib: 102334155
Evil A's Fib: 165580141
Evil A's Fib: 267914296
Evil A's Fib: 433494437
Evil A's Fib: 701408733
Evil A's Fib: 1134903170
Evil A's Fib: 1836311903
Evil A's Fib: 2971215073
Evil A's Fib: 4807526976
Evil A's Fib: 7778742049
------
Test Loop On Evil B

Test start
lazy1 Evil B's Fib: 0
lazy2 Evil B's Fib: 1
lazy3 Evil B's Fib: 1
lazy4 Evil B's Fib: 2
lazy5 Evil B's Fib: 3
lazy6 Evil B's Fib: 5
lazy7 Evil B's Fib: 8
lazy8 Evil B's Fib: 13
lazy9 Evil B's Fib: 21
lazy10 Evil B's Fib: 34
lazy11 Evil B's Fib: 55
lazy12 Evil B's Fib: 89
lazy13 Evil B's Fib: 144
lazy14 Evil B's Fib: 233
lazy15 Evil B's Fib: 377
lazy16 Evil B's Fib: 610
lazy17 Evil B's Fib: 987
lazy18 Evil B's Fib: 1597
lazy19 Evil B's Fib: 2584
lazy20 Evil B's Fib: 4181
lazy21 Evil B's Fib: 6765
lazy22 Evil B's Fib: 10946
lazy23 Evil B's Fib: 17711
lazy24 Evil B's Fib: 28657
lazy25 Evil B's Fib: 46368
lazy26 Evil B's Fib: 75025
lazy27 Evil B's Fib: 121393
lazy28 Evil B's Fib: 196418
lazy29 Evil B's Fib: 317811
lazy30 Evil B's Fib: 514229
lazy31 Evil B's Fib: 832040
lazy32 Evil B's Fib: 1346269
lazy33 Evil B's Fib: 2178309
lazy34 Evil B's Fib: 3524578
lazy35 Evil B's Fib: 5702887
lazy36 Evil B's Fib: 9227465
lazy37 Evil B's Fib: 14930352
lazy38 Evil B's Fib: 24157817
lazy39 Evil B's Fib: 39088169
lazy40 Evil B's Fib: 63245986
lazy41 Evil B's Fib: 102334155
lazy42 Evil B's Fib: 165580141
lazy43 Evil B's Fib: 267914296
lazy44 Evil B's Fib: 433494437
lazy45 Evil B's Fib: 701408733
lazy46 Evil B's Fib: 1134903170
lazy47 Evil B's Fib: 1836311903
lazy48 Evil B's Fib: 2971215073
lazy49 Evil B's Fib: 4807526976
lazy50 Evil B's Fib: 7778742049
------
TestPick8thOnEvilA
eager1 eager2 eager3 eager4 eager5 eager6 eager7 eager8 eager9 eager10 eager11 eager12 eager13 eager14 eager15 eager16 eager17 eager18 eager19 eager20 eager21 eager22 eager23 eager24 eager25 eager26 eager27 eager28 eager29 eager30 eager31 eager32 eager33 eager34 eager35 eager36 eager37 eager38 eager39 eager40 eager41 eager42 eager43 eager44 eager45 eager46 eager47 eager48 eager49 eager50 
Evil A's 8th fibonacci is 13
------
TestPick8thOnEvilB
lazy1 lazy2 lazy3 lazy4 lazy5 lazy6 lazy7 lazy8 
Evil B's 8th fibonacci is 13
------



Live Code: http://ideone.com/QxU7Sn

No comments:

Post a Comment