## Friday, September 28, 2007

### Ruby's yield statement

Ruby provides a yield statement that eases the creation of iterators.

The first thing I noticed was that its behavior is different from the C# yield statement (which I knew from before).

Ruby's yield statement gives control to a user specified block from the method's body. A classic example is the Fibonacci Sequence:

``class NumericSequences   def fibo(limit)     i = 1     yield 1      yield 1      a = 1     b = 1     while (i < limit)         t = a         a = a + b         b = t         yield a         i = i+1     end  end   ...end``

The `fibo` method can be used by specifying a block that will be executed each time the control reaches a `yield` statement. For example:

``irb(main):001:0> g = NumericSequences::new=> #<NumericSequences:0xb7cd703c>irb(main):002:0> g.fibo(10) {|x| print "Fibonacci number: #{x}\n"}Fibonacci number: 1Fibonacci number: 1Fibonacci number: 2Fibonacci number: 3Fibonacci number: 5Fibonacci number: 8Fibonacci number: 13Fibonacci number: 21Fibonacci number: 34Fibonacci number: 55Fibonacci number: 89``

The following example shows the sequence of numbers of a specific row of the Pascal's triangle :

``  def pascal_triangle_row(n)      for k in 0..n          yield(fact(n)/(fact(k)*fact(n-k)))     end  end``

This method can be used like this:

``irb(main):001:0> g = NumericSequences::new=> #<NumericSequences:0xb7c9103c>irb(main):002:0> (0..8).each {|n| g.pascal_triangle_row(n) {|r| print "#{r} "}; print "\n"}1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 => 0..8``

Methods using the `yield` statement can be combined. For example in order to create the sequence of Pascal's triangle read by rows we can write:

``  def pascal(limit_row)     i = 0     while (i <= limit_row)        pascal_triangle_row(i){|x| yield(x)}       i = i+1     end   end``

And use it the same way:

``irb(main):005:0> g.pascal(10) {|x| print "#{x} "}1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 1 1 10 45 120 210 252 210 120 45 10 1 => nil``

#### 6 comments: Anonymous said...

Could you explain how this is different than C#'s yeild? It looks to be doing the same thing from the examples you gave. Am I missing something?

Luis Diego Fallas said...

Sorry I didn't explain why I think c#'s yield is different.

I think there's no big difference, but for me, the way you use the result of a method call is different.

In C# when you use yield the type of the method must be IEnumerable<T> where T is the type of the element you are returning. This means you can pass the result of a calling that method to another method or assign it to a variable. For example:

class P {

IEnumerable<int> Numbers()
{
yield return 1;
yield return 2;
yield return 3;
}

void UseNumbers()
{
IEnumerable<int> v = Numbers();
Foo(Numbers());
}

void Foo(IEnumerable<int> g)
{
foreach(int i in g ) {
Console.WriteLine(i);
}
}
}

From my limited Ruby knowledge, I think the difference is that in order to use a method that has yield you need to specify a block as an argument of the method call (like in the example I use in this post).

If you want to pass the result you can use Enumerator::Enumerable class.

r = P::new

def foo(e)
e.each { |i| print i}
end

en = Enumerator::Enumerable::new(r,:numbers)
foo(en)

Luis Diego Fallas said...

One think I didn't know how to implement using Ruby's yield is how to create an infinite sequence of values , combine it with other sequences and take only some elements of the sequence (which was the original example I was trying to implement for this post). For example in C# you can write:

IEnumerable<int> Odd()
{
int i = 1;
while(true)
{
if (i % 2 != 0) {
yield return i;
}
i++;
}
}
IEnumerable<int> Even()
{
int i = 1;
while(true)
{
if (i % 2 == 0) {
yield return i;
}
i++;
}
}
IEnumerable<T> Mix<T>(IEnumerable<T> e1,IEnumerable<T> e2)
{
IEnumerator<T> i1 = e1.GetEnumerator();
IEnumerator<T> i2 = e2.GetEnumerator();
bool c1 = true;
bool c2 = true;
while (c1 || c2)
{
if (i1.MoveNext())
{
yield return i1.Current;
} else {
c1 = false;
}
if (i2.MoveNext())
{
yield return i2.Current;
} else {
c2 = false;
}
}
}

IEnumerable<T> Take<T>(int n,IEnumerable<T> e) {
int i =1;
foreach(T r in e)
{
if (i > n)
break;
yield return r;
i++;
}
}

You can write the following code:

foreach(int i in Take(6,Mix(Odd(),Even())) ) {
Console.WriteLine(i);
}

And the program will print only the numbers from 1 to 6.

I'm going to read more to see if this could be implemented. Jules said...

Here's a neater version of fibo:

def fibs(x)
a = b = 1
x.times{yield a; a,b = b,a+b}
end

to be used like this:

fibs(10){|fib| puts fib}

Luis Diego Fallas said...

Very nice!

Xetas said...

As far as I know yield in Ruby is just syntax sugar for calling implicit last lambda parameter. So it's less powerful then Python's or C#'s analogs. E.g. in python one can write following, but not in Ruby:

def indices(n):
. i = 0
. while n>i:
.. yield i
.. i += 1

def fib():
. a = b = 1
. while True:
.. yield a
.. a,b = b,a+b

list(zip(index(5), fib()))