yield... - No Fluff Just Stuff

yield...

Posted by: Venkat Subramaniam on July 8, 2005

You have read about coroutines. I remember learning it in a programming theory and languages courses. >

 

When you make a function call, you jump to that function, execute it and return back to the calling

function. A recursive call is where a function call?s itself, however, you complete the instructions in the

called function?s context (stack), before returning to the execution of instructions in the caller?s context.  

A coroutine is where the control flows between a pair of methods back and forth as shown here:

In the next version of C# (2005) the yield statement facilitates this. The yield statement in C# comes with

some restrictions. It is used as part of the iterator. You can use it in methods that return an iterator (Enumerator)

or Enumerable.

 

When the yield statement is reached the control transfers to the caller of the method. When the caller

iterates over to the next item in the collection, the statement after the yield (if any) is executed in the

method. The syntax of yield is

yield return whatever;   >

or

yield break;

Let?s look at an example of using yield in C#. Assume a method GetValue1() is going to create a series of

numbers and you are interested in displaying these numbers. The code may be written as shown below:

public static List<int> GetValues1(int number)
{
   List<int> result = new List<int>();
   for (int i = 0; i <= number; i++)
   {
      result.Add(i);
      // Delay to simulate some compute intense operation
      System.Threading.Thread.Sleep(100);
   }

   return result;
}

I can call this method like the example below:

foreach (int val in GetValues1(10))
{
   Console.Write(val + " ");
}
Console.WriteLine();

When you execute this code, you will notice that there is a delay (of 1 second) and then the output displays

numbers 0 to 10. What if you don?t want to delay the output of the result, that is, you want to display the

numbers as they are being generated. Of course, I could put the display in the GetValue1() method itself,

but that would be wrong. What if I don?t want to display but do something else with the values being

generated? The code that generates the values (GetValue1()) must be separate from the code that uses it. This

is where yield can help. Let?s implement the GetValue1() method differently. I am naming this newer version

GetValue2():

public static IEnumerable<int> GetValues2(int number)
{
   for (int i = 0; i <= number; i++)
   {
      yield return i;
      // Delay to simulate some compute intense operation
      System.Threading.Thread.Sleep(100);
   }
}

In this example, I am looping through the numbers and as I generate a value (in this example, trivially, the

number generated is the index of the loop itself), I return that number with a yield. This differs from the

regular return in that you are not returning back to the caller so as to never come back. Once the caller processes

the returned value, the code continues to execute any statement after the yield. Here is how I would use this

code:

foreach (int val in GetValues2(10))
{
   Console.Write(val + " ");
}
Console.WriteLine();

You see no difference in how you use the two methods GetValue1() and GetValue2(). However, the behavior is

different. In this case, instead of a 1 second delay, after a 100ms delay, the first number 0 is displayed,

followed by the second number after another 100ms delay and so on.

 

Click here to see a simulation of the execution of above code.

 

>

 

I will discuss more about yield in a future article at the download page.

 

The yield statement in Ruby is a lot more elegant. Here is the above example (GetValue2()) written in Ruby:

def GetValue2(number)
    for i in 0..number
        yield i
        sleep(0.1)
    end
end

puts ?Calling GetValue2?
GetValue2(10) { |val| print val.to_s + ' '}

The call to GetValue2() is given a parameter of 10. The {} following that is the statement that will be

executed for each call to the yield statement within GetValue2(). The value that is returned by yield, that is i,  
is
referred in the caller side as val (declared within the ||). Click here for the output from the above code.

Nice feature.


Venkat Subramaniam

About Venkat Subramaniam

Dr. Venkat Subramaniam is an award-winning author, founder of Agile Developer, Inc., creator of agilelearner.com, and an instructional professor at the University of Houston.

He has trained and mentored thousands of software developers in the US, Canada, Europe, and Asia, and is a regularly-invited speaker at several international conferences. Venkat helps his clients effectively apply and succeed with sustainable agile practices on their software projects.

Venkat is a (co)author of multiple technical books, including the 2007 Jolt Productivity award winning book Practices of an Agile Developer. You can find a list of his books at agiledeveloper.com. You can reach him by email at venkats@agiledeveloper.com or on twitter at @venkat_s.

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 8
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 4
  • Cloud
  • Automation Tools: Gradle, Git, Jenkins, Sonar
  • HTML5, CSS3, AngularJS, jQuery, Usability
  • Mobile Apps - iPhone and Android
  • More...
Learn More »