Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Passing a named function instead of a code block?

Reply
Thread Tools

Passing a named function instead of a code block?

 
 
Paul Jungwirth
Guest
Posts: n/a
 
      03-20-2009
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-forum.com/.

 
Reply With Quote
 
 
 
 
Matthias Reitinger
Guest
Posts: n/a
 
      03-20-2009
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-forum.com/.

 
Reply With Quote
 
 
 
 
7stud --
Guest
Posts: n/a
 
      03-20-2009
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-forum.com/.

 
Reply With Quote
 
James Coglan
Guest
Posts: n/a
 
      03-20-2009
[Note: parts of this message were removed to make it a legal post.]

2009/3/20 7stud -- <(E-Mail Removed)>

> 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.com/jcoglan

 
Reply With Quote
 
7stud --
Guest
Posts: n/a
 
      03-20-2009
James Coglan wrote:
> 2009/3/20 7stud -- <(E-Mail Removed)>
>
>>
>> (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-forum.com/.

 
Reply With Quote
 
James Coglan
Guest
Posts: n/a
 
      03-20-2009
[Note: parts of this message were removed to make it a legal post.]

2009/3/20 7stud -- <(E-Mail Removed)>

> James Coglan wrote:
> > 2009/3/20 7stud -- <(E-Mail Removed)>
> >
> >>
> >> (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.com/jcoglan

 
Reply With Quote
 
Paul Jungwirth
Guest
Posts: n/a
 
      03-20-2009
Matthias Reitinger wrote:
> puts c.collect(&method(:fib))


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

 
Reply With Quote
 
Paul Jungwirth
Guest
Posts: n/a
 
      03-20-2009
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-forum.com/.

 
Reply With Quote
 
James Coglan
Guest
Posts: n/a
 
      03-20-2009
[Note: parts of this message were removed to make it a legal post.]

2009/3/20 Paul Jungwirth <(E-Mail Removed)>

> 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.html#M000338

 
Reply With Quote
 
Paul Jungwirth
Guest
Posts: n/a
 
      03-20-2009
James Coglan wrote:
> See docs for Object#method:
> http://ruby-doc.org/core/classes/Object.html#M000338


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-forum.com/.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Named argument passing, and method_args extension Brian Candler Ruby 3 09-10-2007 10:33 AM
Passing variable number of named arguments Ramashish Baranwal Python 2 12-28-2006 05:36 AM
How do I get code to fire on the HTML page instead of the code behind? aaa ASP .Net 3 05-05-2005 11:08 PM
Passing a C++ object's member function to a C function expecing a function pointer! James Vanns C++ 7 01-21-2004 02:39 AM
Re: function objects instead of function pointers? Brian C++ 2 10-31-2003 01:45 PM



Advertisments