Skip to content

More Ruby blocks

Wednesday, 22 September 2004  |  richard dale

Michael writes more about ruby blocks:

What I have yet to do, however, is find a way to get braces to work with if, while, or other flow-control type statements. For example, the program yes implemented in Ruby:

while true
    print "y\n"
end 

To do that with curly braces you need this:

loop {
    print "y\n"
}

But ruby blocks aren't really like C blocks. A C block introduces a new nested lexical scope. For instance:

void my_func() 
{
int a = 5;
printf("a: %d\n", a);
    {  
        int a = 4;
        printf("a: %d\n", a);
    }
}

Will print:

a: 5
a: 4

The nested 'a' variable has a value of 4, which overrides the outer one of value 5 in the second printf().

Perhaps the best way to think about a ruby block in C terms, is as a function pointer which carries with it a snapshot of its environment. For instance:

class Klass
    def setupBlock(&a_block)
        @my_block = a_block
    end
 
    def callBlock()
        a = 4
        @my_block.call()
    end
end

obj = Klass.new
a = 5
obj.setupBlock() { puts "a: #{a}" }
obj.callBlock

Will print

a: 5

Even though the local variable 'a' is set to 4 inside the method callBlock(). This is because the block has taken a snapshot of the top level where 'a' was set to 5. You pass a block to a method by prefixing the arg name with an ampersand:

def setupBlock(&a_block)

The type of the parameter a_block is 'Proc', and you can invoke it with the Proc.call() method, ie '@my_block.call()'.