How to pass a function as argument in ruby?


#1

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:inx’
from (irb):42
from :0


#2

Hi –

On Mon, 13 Feb 2006, the_crazy88 wrote:

y(x)

Result is 7

But the equivalent ruby code doesn’t work:

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

NoMethodError: undefined method b' for main:Object from (irb):40:inx’
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


David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light (http://www.rubypowerandlight.com)

“Ruby for Rails” chapters now available
from Manning Early Access Program! http://www.manning.com/books/black


#3

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

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

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 G. II


#4

the_crazy88 wrote:

end

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

NoMethodError: undefined method b' for main:Object from (irb):40:inx’
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.


#5

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


#6

DÅ?a Nedeľa 12 Február 2006 22:48 Timothy H. napísal:

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


#7

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


#8

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


#9

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