Beginner help

J

Justin To

Hello, I have just started learning Ruby and have already come upon a
problem:

i'm learning and blocks and procs:

def meth(proc)
puts "before proc"
proc.call
puts "after proc"

yield("hi")

if block_given?
puts "block exists"
else puts "D.N.E."
end
end

meth proc {|var1| puts "block" }

prc = lambda do
puts "inside proc"
end

meth(prc)

the main thing i don't understand is how to create a block when the
original method has an argument? and the block takes an argument....

def meth(proc)

meth proc {|var1| puts "block" }
 
D

David A. Black

Hi --

Hello, I have just started learning Ruby and have already come upon a
problem:

i'm learning and blocks and procs:

def meth(proc)
puts "before proc"
proc.call
puts "after proc"

yield("hi")

if block_given?

If there's no block, that yield is going to have caused an exception
anyway.
puts "block exists"
else puts "D.N.E."
end
end

meth proc {|var1| puts "block" }

prc = lambda do
puts "inside proc"
end

meth(prc)

the main thing i don't understand is how to create a block when the
original method has an argument? and the block takes an argument....

def meth(proc)

meth proc {|var1| puts "block" }

meth(proc) {|var1| puts "block" }

Is that what you mean?


David
 
J

Justin To

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?

Thanks in advance.
 
D

David Masover

def meth(proc)
yield("hello")
end

meth(proc) {|var1| puts "block" }

I'm not sure that's right. Basic way to do this would be:

def meth
yield("hello")
end

meth { |var1| puts "block" }

Looking at your original message, are you wanting to do this with two
blocks/procs? For example:

def meth(some_proc)
some_proc.call 'calling proc'
yield 'calling block'
end

meth(lambda{|x| puts x; puts 'in proc'}) {|x puts x; puts 'in block'}

That is really, really cumbersome to use. I haven't found a good way around
it, though...
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

The 'proc' method, by itself, is trying to create a Proc object. So, for
example:

foo = proc { |var1| puts "block" }

Now "foo" is the proc, and can be passed around.
 
S

Simon Krahnke

* Justin To said:
What does this mean? What did I do wrong?

You are confusing blocks and procs. Every method can have a single
block, which can be tested by block_given? and called by yield. Procs
are Objects that have a call method.

There is no special syntax for defining a method that takes a block:

,----
| def a
| yield 1
| end
|
| a { | n | puts n }
|
| def b(arg)
| yield 1 + arg
| end
|
| b(1) { | n | puts n }
`----

You can turn a block into a Proc:

,----
| def c(&block)
| block.call 1
| end
|
| def d(arg, &block)
| block.call(1 + arg)
| end
`----

That's in fact what the proc method does:

,----
| p = proc { | n | puts n }
| p.call 1
`----

mfg, simon .... l
 
B

benjohn

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top