[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Passing a named function instead of a code block?

Paul Jungwirth

3/20/2009 2:16:00 AM

Hello,

I have a question about ruby's feature that when you call a method, you
can pass in a block of code after the last argument. Instead of writing
a code block, suppose I already have a def'd method that would work just
as well. Is there any way I can pass that in directly? For example,
suppose I have this code:

#!/usr/bin/env ruby

def fib(n)
a, b = 0, 1
n.times do |i|
a, b = b, a+b
end
b
end

c = [1, 2, 3, 4]

puts c.collect {|i| fib i}

That will print fib(1), fib(2), fib(3), fib(4). But why write a code
block that takes one argument and does nothing but call a function that
takes one argument? Is there some way I could have replaced the last
line with something like this?:

puts c.collect \fib

In python I could have written the last line thus:

print map(fib, (1, 2, 3, 4))

Does ruby have something similar?

Thanks,
Paul
--
Posted via http://www.ruby-....

12 Answers

Matthias Reitinger

3/20/2009 2:40:00 AM

0

Paul Jungwirth wrote:
> I have a question about ruby's feature that when you call a method, you
> can pass in a block of code after the last argument. Instead of writing
> a code block, suppose I already have a def'd method that would work just
> as well. Is there any way I can pass that in directly? For example,
> suppose I have this code:
>
> #!/usr/bin/env ruby
>
> def fib(n)
> a, b = 0, 1
> n.times do |i|
> a, b = b, a+b
> end
> b
> end
>
> c = [1, 2, 3, 4]
>
> puts c.collect {|i| fib i}

puts c.collect(&method(:fib))

-Matthias
--
Posted via http://www.ruby-....

7stud --

3/20/2009 8:50:00 AM

0

Matthias Reitinger wrote:
>
> puts c.collect(&method(:fib))
>

Why is there a difference here:

def square1(x)
x*x
end

square2 = lambda { |x| x*x}

puts [1, 2, 3].collect(&square2)
puts [1, 2, 3].collect(&square1)

--output:--
1
4
9
r1test.rb:8:in `square1': wrong number of arguments (0 for 1)
(ArgumentError)
from r1test.rb:8


Why does ruby make you use the tortured syntax:

&method(:square1)

for a method vs. the easier syntax for a Proc object?


--
Posted via http://www.ruby-....

James Coglan

3/20/2009 9:07:00 AM

0

[Note: parts of this message were removed to make it a legal post.]

2009/3/20 7stud -- <bbxx789_05ss@yahoo.com>

> Matthias Reitinger wrote:
> >
> > puts c.collect(&method(:fib))
> >
>
> Why is there a difference here:
>
> def square1(x)
> x*x
> end
>
> square2 = lambda { |x| x*x}
>
> puts [1, 2, 3].collect(&square2)
> puts [1, 2, 3].collect(&square1)
>
> --output:--
> 1
> 4
> 9
> r1test.rb:8:in `square1': wrong number of arguments (0 for 1)
> (ArgumentError)
> from r1test.rb:8
>
>
> Why does ruby make you use the tortured syntax:
>
> &method(:square1)
>
> for a method vs. the easier syntax for a Proc object?



square2 is a variable name (ie. something you've made an assignment to),
it's just a reference to the lambda object. However, square1 is a method and
Ruby allows calling methods without parens, so 'square1' is actually
interpreted as a method call to square1 with no arguments. Therefore, to
grab a method as an object without calling it, we need to use
method(:square1).

--
James Coglan
http://github.c...

7stud --

3/20/2009 10:03:00 AM

0

James Coglan wrote:
> 2009/3/20 7stud -- <bbxx789_05ss@yahoo.com>
>
>>
>> (ArgumentError)
>> from r1test.rb:8
>>
>>
>> Why does ruby make you use the tortured syntax:
>>
>> &method(:square1)
>>
>> for a method vs. the easier syntax for a Proc object?
>
>
>
> square2 is a variable name (ie. something you've made an assignment to),
> it's just a reference to the lambda object. However, square1 is a method
> and
> Ruby allows calling methods without parens, so 'square1' is actually
> interpreted as a method call to square1 with no arguments. Therefore, to
> grab a method as an object without calling it, we need to use
> method(:square1).

Ok. But there is a certain amount of hypocrisy in that explanation
Look here:

&square1
:square1

In the first expression there is a method call, and in the second there
isn't. Yet, you could describe both those lines as: a method name
preceded by some symbol.



--
Posted via http://www.ruby-....

James Coglan

3/20/2009 10:16:00 AM

0

[Note: parts of this message were removed to make it a legal post.]

2009/3/20 7stud -- <bbxx789_05ss@yahoo.com>

> James Coglan wrote:
> > 2009/3/20 7stud -- <bbxx789_05ss@yahoo.com>
> >
> >>
> >> (ArgumentError)
> >> from r1test.rb:8
> >>
> >>
> >> Why does ruby make you use the tortured syntax:
> >>
> >> &method(:square1)
> >>
> >> for a method vs. the easier syntax for a Proc object?
> >
> >
> >
> > square2 is a variable name (ie. something you've made an assignment to),
> > it's just a reference to the lambda object. However, square1 is a method
> > and
> > Ruby allows calling methods without parens, so 'square1' is actually
> > interpreted as a method call to square1 with no arguments. Therefore, to
> > grab a method as an object without calling it, we need to use
> > method(:square1).
>
> Ok. But there is a certain amount of hypocrisy in that explanation
> Look here:
>
> &square1
> :square1
>
> In the first expression there is a method call, and in the second there
> isn't. Yet, you could describe both those lines as: a method name
> preceded by some symbol.


Yes, it probably looks that way. To see the difference it helps to know how
Ruby is parsed. :square1 is an atomic unit representing the symbol whose
name is 'square1'. ":" is not an operator, it is part of the syntax for
symbols. However, "&" is an operator responsible for casting between procs
and blocks. The expression '&square1' should be read '&( square1 )', that is
we call square1 and cast the result of that using '&'. The same applies to
'method'. 'method' is a method that takes a symbol/string and returns the
Method object with that name in the current scope. 'method(square1)' would
be interpreted as a call to square1, passing the result to 'method'.

So, '&square1' throws an error because you're calling a method with
insufficient arguments. '&:square1' would try to cast a symbol to a proc,
which if you're using ActiveSupport would return the block { |object|
object.square1 }.

'&square2' is fine as square2 is just a variable referring to a proc.
Likewise, '&method(:square1)' is fine because method(:square1) is a Method
object, which can be cast to a block.

--
James Coglan
http://github.c...

Paul Jungwirth

3/20/2009 11:05:00 AM

0

Matthias Reitinger wrote:
> puts c.collect(&method(:fib))

Thank you for your help; this does just what I wanted.
--
Posted via http://www.ruby-....

Paul Jungwirth

3/20/2009 11:38:00 AM

0

Okay, now how about when you want to reference a method on an instance?
For example:

#!/usr/bin/env ruby

class Adder
def initialize(n)
@n = n
end

def use(x)
x + n
end
end


a = Adder.new(5)

print [1, 2, 3, 4].collect(&method(:a.use))

This doesn't work. It looks like : binds tighter than .. But :(a.use)
doesn't work either. Any suggestions?

--
Posted via http://www.ruby-....

James Coglan

3/20/2009 11:40:00 AM

0

[Note: parts of this message were removed to make it a legal post.]

2009/3/20 Paul Jungwirth <once@9stmaryrd.com>

> Okay, now how about when you want to reference a method on an instance?
> For example:
>
> #!/usr/bin/env ruby
>
> class Adder
> def initialize(n)
> @n = n
> end
>
> def use(x)
> x + n
> end
> end
>
>
> a = Adder.new(5)
>
> print [1, 2, 3, 4].collect(&method(:a.use))
>
> This doesn't work. It looks like : binds tighter than .. But :(a.use)
> doesn't work either. Any suggestions?


a.method(:use)

See docs for Object#method:
http://ruby-doc.org/core/classes/Object.ht...

Paul Jungwirth

3/20/2009 1:06:00 PM

0

James Coglan wrote:
> See docs for Object#method:
> http://ruby-doc.org/core/classes/Object.ht...

Ah, so I want a line like this:

puts [1, 2, 3, 4].collect(&a.method(:use))

Actually, this helps me understand the previous solution. I guess
method(:foo) and a.method(:foo) are actually going to the same place,
huh? And each return a Method object, which I then cast to a block with
&. It is all starting to make sense....

Doesn't this seem like an appropriate place for some syntactic sugar?
I'd be nice if you could abbreviate such calls with something like:
\:foo
\:a.foo
Since ruby is so focused on closures, this seems like an appropriate
place for such brevity.

Thanks again!


--
Posted via http://www.ruby-....

7stud --

3/22/2009 3:21:00 AM

0

James Coglan wrote:
> 2009/3/20 7stud -- <bbxx789_05ss@yahoo.com>
>
>> >> &method(:square1)
>> > grab a method as an object without calling it, we need to use
>> preceded by some symbol.
> Yes, it probably looks that way. To see the difference it helps to know
> how
> Ruby is parsed. :square1 is an atomic unit representing the symbol whose
> name is 'square1'. ":" is not an operator, it is part of the syntax for
> symbols. However, "&" is an operator responsible for casting between
> procs
> and blocks. The expression '&square1' should be read '&( square1 )',
> that is
> we call square1 and cast the result of that using '&'. The same applies
> to
> 'method'. 'method' is a method that takes a symbol/string and returns
> the
> Method object with that name in the current scope. 'method(square1)'
> would
> be interpreted as a call to square1, passing the result to 'method'.
>
> So, '&square1' throws an error because you're calling a method with
> insufficient arguments. '&:square1' would try to cast a symbol to a
> proc,
> which if you're using ActiveSupport would return the block { |object|
> object.square1 }.
>
> '&square2' is fine as square2 is just a variable referring to a proc.
> Likewise, '&method(:square1)' is fine because method(:square1) is a
> Method
> object, which can be cast to a block.

Thanks for the explanation. You said that (&) casts between block and
Procs. But (&) also appears to be casting a Method to a block in this
line:

puts c.collect(&method(:fib))

(&) can also be used to cast in the reverse direction, e.g. from a block
to a Proc:

def test(&aProc)
aProc.call(10)
end

test {|x| puts x}

--output:--
10


Can (&) cast a block to a Method?

--
Posted via http://www.ruby-....