I’m doing a SaaS course with Ruby. On an exercise, I’m asked to calculate the cartesian product of two sequences by using iterators, blocks and yield.
I ended up with this, by pure guess-and-error, and it seems to work. But I’m not sure about how. I seem to understand the basic blocks and yield usage, but this? Not at all.
class CartProd
include Enumerable
def initialize(a,b)
@a = a
@b = b
end
def each
@a.each{|ae|
@b.each{|be|
yield [ae,be]
}
}
end
end
Some explanation for a noob like me, please?
(PS: I changed the required class name to CartProd so people doing the course can’t find the response by googling it so easily)
Let’s build this up step-by-step. We will simplify things a bit by taking it out of the class context.
For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.
So first here’s a for-loop version:
Now let’s replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the
do...endblocks):So far, so good, you’ve printed out your cartesian product. Now your assignment asks you to use
yieldas well. The point ofyieldis to “yield execution”, i.e., pass control to another block of code temporarily (optionally passing one or more arguments).So, although it’s not really necessary for this toy example, instead of directly printing the value like above, you can
yieldthe value, and let the caller supply a block that accepts that value and prints it instead.That could look like this:
Callable like this:
The
yieldsupplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.