How to pass a function as argument in ruby?

I've searched a bit about the subject, but I don't understand it. All I
want is to simply pass a function of one instance to another. In Python
this works, but in ruby not.

Python code would be:
def x(a,b):
  return a+b

def y(a):
  return a(3,4)

y(x)
# Result is 7
But the equivalent ruby code doesn't work:

def a(x,y)
  return x+y
end

def x(b)
  return b(3,4)
end

x(a)
#Gives the following error in irb:

NoMethodError: undefined method `b' for main:Object
        from (irb):40:in `x'
        from (irb):42

···

from :0

Hi --

I've searched a bit about the subject, but I don't understand it. All I
want is to simply pass a function of one instance to another. In Python
this works, but in ruby not.

Python code would be:
def x(a,b):
return a+b

def y(a):
return a(3,4)

y(x)
# Result is 7
But the equivalent ruby code doesn't work:

That's because it's not equivalent :slight_smile:

def a(x,y)
return x+y
end

def x(b)
return b(3,4)
end

x(a)
#Gives the following error in irb:

NoMethodError: undefined method `b' for main:Object
       from (irb):40:in `x'
       from (irb):42
       from :0

It shouldn't; it should complain that you've called a with no
arguments instead of two.

When you do this:

   x(a)

Ruby evaluates the expression 'a', and that's a method call -- so it
tries to call the method a, but that method takes two arguments and
you haven't provided any.

You can pass method names around, as strings or symbols, and then
"send" the method name to an object (or self, by default):

   def a(x,y)
     x + y
   end

   def x(b)
     send(b,3,4)
   end

   puts x(:a) # 7

There are also some more elaborate mechanisms involving Method
objects, but the above might achieve what you need.

David

···

On Mon, 13 Feb 2006, the_crazy88 wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

You can ask for a method object and call it when needed:

def a(x,y)
   return x+y
end

def x(b)
   return b.call(3,4)
end

p x(method(:a))

Hope that helps.

James Edward Gray II

···

On Feb 12, 2006, at 3:23 PM, the_crazy88 wrote:

But the equivalent ruby code doesn't work:

def a(x,y)
  return x+y
end

def x(b)
  return b(3,4)
end

x(a)
#Gives the following error in irb:

the_crazy88 wrote:

I've searched a bit about the subject, but I don't understand it. All I
want is to simply pass a function of one instance to another. In Python
this works, but in ruby not.

def a(x,y)
   return x+y
end

def x(b)
   return b.call(3,4)
end

puts(x(method(:a)))

# or the ruby way:

def x
   yield 3, 4
end

puts(x{|a, b| a + b})

cheers

Simon

the_crazy88 wrote:

I've searched a bit about the subject, but I don't understand it. All I
want is to simply pass a function of one instance to another. In Python
this works, but in ruby not.

Python code would be:
def x(a,b):
  return a+b

def y(a):
  return a(3,4)

y(x)
# Result is 7
But the equivalent ruby code doesn't work:

def a(x,y)
  return x+y
end

def x(b)
  return b(3,4)
end

x(a)
#Gives the following error in irb:

NoMethodError: undefined method `b' for main:Object
        from (irb):40:in `x'
        from (irb):42
        from :0

In Ruby it's typical to encapsulate bits of code in Proc objects and pass these objects around:

p = Proc.new {|x,y} x+y}

p.call(2,3) -> 5

If you're really wanting to pass methods around from one instance to another, check out the doc for the UnboundMethod class with ri.

Dňa Nedeľa 12 Február 2006 22:48 Timothy Hunter napísal:

the_crazy88 wrote:

In Ruby it's typical to encapsulate bits of code in Proc objects and
pass these objects around:

p = Proc.new {|x,y} x+y}

p.call(2,3) -> 5

If you're really wanting to pass methods around from one instance to
another, check out the doc for the UnboundMethod class with ri.

Or use Procs and inject the instance into them as a parameter, which is a bit
more readable to me.

David Vallner

Ok, thanks a lot everyone! Seems like a lot of usefull ideas.

Though I tried your suggestions, something worked out much better. I
just needed to pass a reference to the calling class with the argument
self. That way I can call back functions just by executing them. For
example:

class Example
  attr_reader :show_info
  def initialize
     @instance = self
     @example2 = Example2.new(@instance)
  end
  def show_info(text)
    puts text
  end
end

class Example2
  def initialize(instance)
    @instance = instance
    @instance.show_info("Yes, this worked out :D")
  end
end

Dňa Utorok 14 Február 2006 07:03 the_crazy88 napísal:

Though I tried your suggestions, something worked out much better. I
just needed to pass a reference to the calling class with the argument
self. That way I can call back functions just by executing them. For
example:

There you go, proper OO instead of functional for the heck of it.

class Example
  attr_reader :show_info

The above line of code is completely unnecessary.

  (snip)

David Vallner