intertwingly

It’s just data

Blocks for Box


Don Box: The underlying language feature (along with its cousin, anonymous methods) do in fact rock though.

Let’s explore further.

How do you call a function in C?

name (parameters)

Now, how do you call a method in C++?

object.method(parameters)

The way the latter works under the covers is that an additional parameter is typically passed, and bound to the name this.  Hold that thought.

Now, lets’s look at a few of the control structures in C#, as they are typically used:

while (parameter) {block}
if (parameter) {block}
for (parameters) {block}
foreach (parameters) {block}
switch (parameter) {block}
lock (parameter) {block}

I’ve taken a few liberties with how I have named things to emphasize similarities, but my key point is that from a simple syntactic point of view, each of these statements look like a procedure call statement, albeit with a funny “extra” block parameter.

And, among these examples, the lock example feels a bit strange.  It feels like a bit of application specific functionality creeping down into the language.  Hold that thought too.

Now, one final example to feed into this mix.  I’ll give a very simple C# example:

public class test {
  public static void Main(string[] args) {
    int[] list = new int[] {1,2,3,4,5,6,7,8,9,10};
    int sum = 0;
    foreach (int i in list) { sum = sum + i; }
    System.Console.WriteLine(sum);
  }
}

Now, I realize that this problem of solving the sum of a series of consecutive integers can be reduced to a simple equation, but dang it, remember that this is meant as an example.  Bear with me.

Now, let’s show how this can be implemented in Ruby:

list = [1,2,3,4,5,6,7,8,9,10]
sum = 0
list.each() {|i| sum = sum + i}
puts sum

Now, if you ignore the people who will tell you that in Ruby the parenthesis are not required, or whisper in your ear inject, inject, inject, and if you ignore the extra pro-forma baggage that C# requires; then you see that there is the same core four statements involved in both implementations.  The third of which looks suspiciously like a procedure/method call like thing — with an extra parameter.

Which, in Ruby, is exactly what it is.

In object oriented systems, there is a bit of mental judo going on whereby you convert a system from imperative statements like “print x” to a more message oriented “to: x; message: go print yourself”.  The same thing is going on here.  In Ruby, you are calling one method, and passing it a block that it can chose to call as many, or as few, times as it likes.  The method can even chose to stash away the block for later use.

The block itself can even be parameterized, as it is above.  In this example, the block expects one parameter, which it names i.

One more interesting thing to note is that the block captures its scope, i.e., it behaves like a closure.  Again referencing this example, the block directly accesses and modifies a value named sum, something which is not visible to the definition of the Array.each method.

How can this be useful?  The lock example above is a specific example whereby the language designers had enough foresight to build a similar feature into the language.  In Ruby, such features need not be a part of the language, as you can build your own.

Here are a few examples, but you can build more.