Passing a named function instead of a code block?

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

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/\.

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/\.

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/\.

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).

···

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?

--
James Coglan

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

James Coglan wrote:

(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.

···

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

--
Posted via http://www.ruby-forum.com/\.

a.method(:use)

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

···

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?

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.

···

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.

--
James Coglan

James Coglan wrote:

See docs for Object#method:
class Object - RDoc Documentation

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/\.

James Coglan wrote:

>> &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?

···

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

--
Posted via http://www.ruby-forum.com/\.

There are no casts in Ruby.

& in a Method call calls #to_proc on an Object and expects it to return a proc. Thats a conversion that has to be done explicitly by the programmer.

& in a Method definition indicates that the argument has to be a Proc or something that responds to #to_proc (or a passed Block) which then gets enforced.

Blocks are Procs (AFAIK, internally, Methods are basically procs as well). The only magic is "yield" together with a block, which to my knowledge doesn't require the construction of a Proc Object that has to be visible to the programmer. But thats up to the implementation.

Regards,
Florian

···

On Mar 22, 2009, at 4:20 AM, 7stud -- wrote:

James Coglan wrote:

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?

--
Florian Gilcher

smtp: flo@andersground.net
jabber: Skade@jabber.ccc.de
gpg: 533148E2

James Coglan wrote:

>> &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))

Actually, its casting a Method to a Proc (by calling to_proc on it)
and then treating the proc as a block. To see that's what is
happening, try this:

class Integer
  def to_proc
    Proc.new { self }
  end
end

(1..10).map(&1)

Can (&) cast a block to a Method?

No. & in a method call always treats a the given proc as a block given
to the method while & in a method definition always makes a block
given to the method as a Proc. Its probably best not to think of this
as "casting" except insofar as the first one "casts" to a proc first
by calling to_proc; blocks aren't objects, and if you do this:

def consume(object=nil)
  if block_given? then yield else object end
end

p = lambda { puts "foo!" }
consume(&p)

You don't get the results you' d get if an object of the
(non-existent) class "Block" was passed to consume, you get the
results you would get if consume was called with a block. So thinking
of & as "casting" an argument to a different class in the method call
is misleading.

···

On 3/21/09, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

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