## 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``