Playing with blocks : Part 1

A while back, I wrote an introduction on code blocks. So if you’re not sure what they are, you should read it first.

Something I find interesting with code blocks is that they create the illusion of being executed at the moment they are written. It’s easy to get fooled, because when you look at code like this :

what’s between the curly braces surely doesn’t look like a parameter passed to the each method. However that’s exactly what’s happening. While the following example would fail (Array each method doesn’t expect any regular parameter), for understanding purpose we could write it this way :

Written that way, it becomes clear that you pass the control over to the each method, letting it manage everything. That being said, most of the time you won’t be able to pass a block that way since most methods expect raw blocks… not Proc objects passed as regular parameters.

Raw blocks and Proc objects

Blocks come in two flavors : Raw and Proc objects. A raw block is not an object, it’s only a chunk of code. Proc objects are blocks wrapped into objects. With a Proc object, your block becomes something more concrete and allows you to invoke methods on it like with any other object. To invoke the block contained inside a Proc object, you have to use it’s “call” method instead of the global yield keyword which is used to invoke raw blocks.

Passing the block
The most usual way to pass a block to a method is to use it’s “raw” form, like so :

When you do so, Ruby does some magic to transmit the block to the receiving method. More about that in a few more paragraphs.

You can also pass a block as a regular parameter to the receiving method by converting it to a Proc object like we did earlier, but for this to work the receiving method needs to expect the block as a regular parameter.

If the method each is implemented in a way to receive a parameter of class Proc, the code will pass. Else, it will fail. There is no more magic when you pass a block that way.

Receiving the block

if you passed a raw block to the receiving method, that method has 2 ways to deal with it.

  1. Use the raw block directly
  2. Convert the raw block into a Proc object and use it

if we choose the first option, we can invoke the block with yield :

As you can see, there is some magic happening here. We don’t see the block in the method definition, but somehow it is there and Ruby knows it. block_given? returns true or false depending if a raw block has been passed or not (we don’t want to invoke something that doesn’t exists). yield invokes the raw block.

Now if we choose the 2nd option, it looks like that :

Again, some magic happened here. If the LAST specified parameter of the receiving method is prefixed with an ampersand, ruby will take the received raw block and convert it into a Proc object. Then, it will assign it to this last parameter. Note that the ampersand sign doesn’t mean “passed by reference” like in some other languages. It is just a character used by Ruby to determine if it must convert a raw block into a proc object. If that bit of information didn’t exist, Ruby wouldn’t know what you are trying to do and “block” would become a parameter like any other one.

#UPDATE 05/30/2007
Ah-ha! Shadowfiend and rx made me realize something. Remember that piece of code ?

> 1. my_block = Proc.new {|item| puts item}
> 2. the_array.each(my_block)

I said it would fail since the “each” method isn’t expecting a normal parameter. Well it’s true… but you can bypass this lil problem by prefixing my_block with an & sign when you call the method, like that :

> 1. my_block = Proc.new {|item| puts item}
> 2. the_array.each(&my_block)

Tada! Thanks for the precision!

What to expect in the next part :

  • Code blocks and scope
  • lambdas

Diving into ruby object model : Part 2

Understanding the “chain”

In my last article, I explained where the various elements of an object were located. Now it’s time to understand what happens at run time when you write the following :

Ahh… A method call! Ruby knows what to do in this situation. Remember that inside “obj” resides a reference to MyClass? Well, ruby follows that reference and looks at the methods in there. It tries to find “my_instance_method”… and it finds it! The call succeeds and everyone in the world is happy, dancing hands in hands like shameless hippies.

Now, if we write :

Once again, ruby follows the reference to “MyClass” and looks for the method “display”. Unfortunately this time, it doesn’t find it. Instead of crying, ruby doesn’t give up and looks for the method in any module that could have been mixed into MyClass (I’ll talk about modules in another post)… but still it can’t find it. Determined as we know it, ruby now follows the reference to the super class (Object) in hope to find that method. Victory, the method is there! The call succeeds.

Once again, ruby follows the reference to MyClass and tries to find “my_class_method”, it isn’t there. It looks in any mixed in module, it isn’t there. It looks in the super class, it isn’t there. It looks in any module that could have been mixed in the super class, it still isn’t there. Now the chain is over, because “Object” has no super class. Ruby invokes “method_missing” and the story ends in a very bad way (people are crying and sobbing to the point that it gets quite embarassing).

But I want to access that class method!

Ah! That looks better. Now the starting point is MyClass instead of obj. Ruby follows the reference to the class of MyClass, let’s call it MetaMyClass (if you hear the expression meta class for the first time, have a look at the first part). Once comfortable inside MetaMyClass, it looks for the method “my_class_method” and guess what? It finds it! The call succeeds.

The chain for class methods

The last paragraph reveals something interesting : there exists a chain for class methods. Now, what if we write :

Since ruby won’t find the method “name” inside MetaMyClass (it’s just a fictional name I gave to the meta class… it isn’t a real ruby class name), what will it do? It will look into the super class of MetaMyClass, which we’ll call MetaObject. MetaObject contains the method “name”… so the call will succeed!

So that’s how this 2-part serie ends. An important but not so obvious thing is the concept of meta classes. To understand their purpose, just tell yourself once again that classes are objects, it’s the key really. If classes are objects, they need a place to store their own methods like any other objects. “obj” stores it’s methods in “MyClass”, “MyClass” stores it’s methods in it’s associated meta class.

Interview on rubyinside.com

A few days ago, Peter Cooper of rubyinside.com gave me an interview about Ruby Fleebie as well as the last project I worked on, Ecstatik!

All in all, it was a great day for me. I hope that those who discovered Ruby Fleebie after reading the interview will enjoy the articles and will stay with the remaining of us for a while!

The next article coming up is : Diving into Ruby object model : part 2. I should publish it sunday night or monday morning.