[prev in list] [next in list] [prev in thread] [next in thread] 

List:       ruby-talk
Subject:    Re: Help with blocks?
From:       "Jason Voegele" <jason () jvoegele ! com>
Date:       2002-02-21 20:19:25
[Download RAW message or body]

> I'm trying to learn Ruby; just started. I like what I've understood
> very much, but I've hit the concept of blocks and bounced. :-( I've
> read the reference manual, and Andy and Dave's book, but I still can't
> seem to grasp what blocks are about. My main difficulty seems to be
> telling the difference between when and how a block is defined, and
> when and how it's used. I'm not even sure that 'defined' and 'used' are
> appropriate concepts. Can anyone explain this to me in words
>simple enough for a C++ programmer to understand? ;-) TIA.

The nearest concept in C++ is the function pointer (or perhaps "function 
objects" or "functors"...haven't kept up with C++ lately).  In essence, 
blocks represent a form of deferred execution.  When you create a block 
(i.e. put some code in { ... } or do ... end) you are defining what the 
block will do when it is called.  Usually, blocks in Ruby are tied to a 
method invocation, meaning that when you call a method and follow the 
method call with a block, you expect the method you are calling to "call 
back" to your block.  For example:

array.each { |element| puts("#{element}") }

Here, you are calling the "each" method of an array, and passing it a block 
(the stuff between the { and }), expecting the each method to call back to 
your block once for each element of the array.  This is accomplished by the 
each method using a "yield" statement for each element in the 
array.  "yield" transfers control to the block associated with a particular 
method invocation.

In C++ terms, you'd have something like the following (forgive any errors 
please ;-)

void myblock(void* element) {
    cout << *element << endl;
}

// assume there's an each method for arrays that takes a function pointer
myarray.each(myblock);

(Someone who's current with C++ can probably give a better example using 
the STL).

The added advantage of Ruby blocks is that (when they are bound to a Proc 
object) they are lexical closures.  This means that the "bundle up" their 
surrounding environment (particularly variables accessed within the block) 
and carry it around with them so that you can pass the block around 
anywhere and it still has access to its environment.  For example:

class Person
    def initialize(name)
        @name = name
    end

    def create_proc
        proc { puts @name }
    end
end

me = Person.new("Jason Voegele")
myproc = me.create_proc
myproc.call   # => prints "Jason Voegele"

By the time you call the block associated with "myproc", the @name variable 
is no longer in scope.  But since Proc objects are closures, the @name 
variable has been "bundled" with the proc object and remains accessible to 
the block regardless of where you pass it around and call it.

Hope this helps.

Jason Voegele



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic