benjohn
6/4/2008 6:29:00 AM
> def meth(proc)
> yield("hello")
> end
>
> meth(proc) {|var1| puts "block" }
>
> Ok... I think I'm just confused about the above example... when i run
> this an error comes up:
> blank.rb:5:in `proc': tried to create Proc object without a block
> (ArgumentError)
> from blank.rb:5
>
> What does this mean? What did I do wrong?
Definitely read the other answers in this thread. I'll try to add some
more explaination.
What's going wrong here is that "proc" is a function in the module Kernal,
and you're trying to use it as a variable (kind of). This will make sense
at the end...
The slightly confusing thing is that Matz thought it was so useful to be
able to pass a bloc to a function, that he included a specicial syntax to
allow at least one to be passed with as little fuss as possible (I think I
agree).
You simply do this:
def meth
yield("hello")
end
meth {|var1| puts "block passed '#{var1}'" }
So the block is passed in as a kind of special hidden argument. The
special function "yield" will call the block that's passed like this. The
rational (which I think is pretty good) is that this is extremely
convenient in the very regular case of only one block being needed by a
function (think of each, map, sort_by, find, find_all, etc).
You can also do this:
def meth(&block_argument)
block_argument.call("hello")
end
meth {|var1| puts "block passed '#{var1}'" }
Here, the "&" notation in "meth"'s definiteion is explicitly picking up
the block that's passed in, and stuffing it in to the parameter
"block_arguent". The class of this thing is a "Proc", which is just an
wrapper object for a block.
Almost finally, you can explicitely build Proc instances using the Kernel
function "proc", which is what you've been inadvertantly calling:
def meth(proc_argument)
proc_argument.call("hello")
end
my_proc = proc {|var1| puts "block passed '#{var1}'" }
meth(my_proc)
Note that here, there's no "&" as part of the definition of "meth" because
proc_argument is a perfectly normal parameter - it's not trying to wrap a
proc passed from the caller.
A further little wrincle is that the "&" can also be used in the oposite way:
def meth
yield("hello")
end
my_proc = proc {|var1| puts "block passed '#{var1}'" }
meth(&my_proc)
... In this case, when used at the call site, it means "take this Proc
instance, unwrap it, and pass it in to the caller using the special block
argument".
Cheers,
Benjohn