Previous Next Table of contents

3. Iterators

3.1 What is an iterator?

Those methods which utilize a block or a Proc object are called iterators.

Iterators are used for abstraction of control structures especially loops.

Let's look at an example to see what it is. Iterators are often used to repeat the same action on each element of a collection, like this:
data = [1, 2, 3]
data.each do |i|
  print i, "\n"
end
This script yields this output.
$ ruby test.rb
1
2
3
That is, the block between do and end is repeatedly executed on each element of an array "data".

Writing in C gives this code.
int data[3] = {1, 2, 3};
int i;
for (i = 0; i < 3; i++) {
  printf("%d\n", data[i]);
}
You must be very careful on the boundary condition when using "for". You are free from such bugs with an iterator.

In place of do...end, you can use {...}.
data = [1, 2, 3]
data.each { |i|
  print i, "\n"
}
This code has the same meaning as the last example. In some cases do...end and {...} act differently.
foobar a, b do .. end # foobar is the iterator.
foobar a, b { .. }    # b is the iterator.
This is because { } attaches stronger to the preceding expression than a do block.

3.2 How can I pass a block to an iterator?

Other than to place a block after an iterator, you can pass a Proc object by prepending & to the variable or constant that refer the Proc object.

3.3 How is a block used in an iterator?

There are three ways to execute a block from an iterator method, namely, yield control structure, a block argument, and Proc.new. ( rb_yield is used in C extension library.)

The yield statement may have arguments which are passed to the block as block parameters and the block is executed.

A block argument appears as the last formal argument with & prepended in the iterator method arguments list. The block is called by method.call(args...) form.

Proc.new, when used in an iterator definition, takes the block which is given to the method as its argument, generates a procedure object generated from the block. The same applies to proc and lambda.
def a (&b)
  yield
  b.call
  Proc.new.call
  proc.call
  lambda.call
end
a{print "test\n"}

3.4 What does Proc.new without a block do?

Proc.new without a block cannot generate a procedure object and an error occurs. In a method definition, Proc.new without a block implies the existence of a block given by the method call.
Previous Next Table of contents