Are blocks objects? What messages can they handle?

Stop me if I’m making any unwarranted assumptions here:

Blocks are basically just a special kind of object passed to a method in
Ruby – aren’t they?

That makes them objects – right?

So . . . how does one send a message to the block before it is passed as
an argument? Is that even possible?

I ask based on curiosity and a desire to better understand the language,
rather than as any kind of need to solve a real-world problem.

A block is a syntactical construct, not an object. A Proc is the
object-ized form of a block. If you want to do something on the block,
you need to turn it into an object first.

An analogy might be that the string “def” is a syntactical construct
that creates a method, but it is not itself an object. You can’t write
“def.(…)” and have it be meaningful in this context.

So . . . how does one send a message to the block before it is passed as
an argument? Is that even possible?

You could make it a Proc first and pass that instead. For example, say
you have a method which passes some arguments to a block:

======

def execute(*args, &block); yield *args if block; end
=> nil

execute(1, 2, 3) { |*args| puts “args are: #{args.inspect}” }
args are: [1, 2, 3]
=> nil
======

Instead of supplying the block, you could pass a block argument:

======

printer = lambda { |*args| puts “args are: #{args.inspect}” }
=> #<Proc:0x0000000125eeb8@(irb):12 (lambda)>

execute(1, 2, 3, &printer)
args are: [1, 2, 3]
======

Since printer is an object, you can call whatever methods you’d like
on it before passing it as a block. Of course, you still need to wind
up with something that looks like a block, or else the yield won’t
work. For example, you might have a Proc that creates printers for
you:

======

printer_factory = lambda { |message_prefix| lambda { |*args| puts
“#{message_prefix}: #{args.inspect}” } }
=> #<Proc:0x000000011f9f90@(irb):17 (lambda)>
======

Now we can ask this Proc to create a printer for us, which we’ll then
pass into execute as a block argument:

======

execute(1, 2, 3, &printer_factory.(“the arguments to this printer are”))
the arguments to this printer are: [1, 2, 3]
======

Make sense?

~ jf

John F.
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: User John Feminella - Stack Overflow

John,
although I was not original question author, wanted to thank you for
that great explanation and example.

stephenb

2011/7/3 John F. [email protected]

On Mon, Jul 04, 2011 at 12:15:54AM +0900, Stephen B. wrote:

John,
although I was not original question author, wanted to thank you for
that great explanation and example.

I was the author of the original question, and I agree. Thanks.

On Sun, Jul 3, 2011 at 12:26 PM, Chad P. [email protected] wrote:

On Mon, Jul 04, 2011 at 12:15:54AM +0900, Stephen B. wrote:

John,
although I was not original question author, wanted to thank you for
that great explanation and example.

I was the author of the original question, and I agree. Thanks.


Chad P. [ original content licensed OWL: http://owl.apotheon.org ]

I found this site to be useful:
http://innig.net/software/ruby/closures-in-ruby.rb

On Sun, Jul 3, 2011 at 5:15 PM, Stephen B. [email protected]
wrote:

John,
although I was not original question author, wanted to thank you for
that great explanation and example.

Just one point of nitpicking:

So . . . how does one send a message to the block before it is passed as
an argument? Is that even possible?

You could make it a Proc first and pass that instead. For example, say
you have a method which passes some arguments to a block:

======

def execute(*args, &block); yield *args if block; end
=> nil

I’d rather use these in pairs because the conversion of a block to an
accessible object has some overhead:

  • block_given? and yield
  • &b and b[] / b.call

So either

def execute(*args)
yield *args if block_given?
end

or

def execute(*args, &block)
block[*args] if block
end

respectively

def execute(*args, &block)
block.call(*args) if block
end

Usually you only need the form with &block if you need to store the
block or pass it on to another method, e.g.

def foo
yield 123
end

def bar(&b)
foo(&b) # pass on
end

bar {|x| p x} # will print 123

Kind regards

robert

That is a fair point, Robert. I didn’t use block_given? because I
wanted to show that indeed, block is an object by the time you can
see it in the method. Using “if block_given?” might not have made that
clear, but I thought that writing “if block” makes it unambiguous that
block is a real object with its own semantics.

~ jf

John F.
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: User John Feminella - Stack Overflow

Jeremy, that was an excellent synopsis of the functionality of blocks,
procs, methods and lambdas. I’m starting to get my head around
anonymous functions, closures and currying.

Thanks.

You can almost feel the authors pain in documenting all that.

If your interested in a colorized version of Paul Cantrell’s tutorial:

http://rubyprogrammer.net/~stu/closures-in-ruby.rb.html