36

In python, it's fairly straightforward to reference a function:

>>> def foo():
...     print "foo called"
...     return 1
... 
>>> x = foo
>>> foo()
foo called
1
>>> x()
foo called
1
>>> x
<function foo at 0x1004ba5f0>
>>> foo
<function foo at 0x1004ba5f0>

However, it seems to be different in Ruby since a naked foo actually calls foo:

ruby-1.9.2-p0 > def foo
ruby-1.9.2-p0 ?>  print "foo called"
ruby-1.9.2-p0 ?>  1
ruby-1.9.2-p0 ?>  end
 => nil 
ruby-1.9.2-p0 > x = foo
foo called => 1 
ruby-1.9.2-p0 > foo
foo called => 1 
ruby-1.9.2-p0 > x
 => 1 

How do I actually assign the function foo to x and then call it? Or is there a more idiomatic way to do this?

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • 1
    check out this article http://www.khelll.com/blog/ruby/ruby-dynamic-method-calling/ since it provides several ways to dynamically call a method. – khelll Nov 27 '10 at 23:43
  • 1
    "a naked foo actually calls foo", yes, Ruby doesn't insist on the parenthesis though I use them to visually separate the parameters from anything following. It's just habit. – the Tin Man Nov 28 '10 at 00:12

4 Answers4

62

Ruby doesn't have functions. It only has methods (which aren't first-class) and Procs which are first-class, but are not associated with any object.

So, this is a method:

def foo(bar) puts bar end

foo('Hello')
# Hello

Oh, and, yes, this is a real method, not a top-level function or procedure or something. Methods defined at the top-level end up as private(!) instance methods in the Object class:

Object.private_instance_methods(false) # => [:foo]

This is a Proc:

foo = -> bar { puts bar }

foo.('Hello')
# Hello

Notice that Procs are called differently from methods:

foo('Hello')  # method
foo.('Hello') # Proc

The foo.(bar) syntax is just syntactic sugar for foo.call(bar) (which for Procs and Methods is also aliased to foo[bar]). Implementing a call method on your object and then calling it with .() is the closest thing you will get to Python's __call__ables.

Note that an important distinction between Ruby Procs and Python lambdas is that there are no restrictions: in Python, a lambda can only contain a single statement, but Ruby doesn't have the distinction between statements and expressions (everything is an expression), and so this limitation simply doesn't exist, therefore in a lot of cases where you need to pass a named function as an argument in Python because you cannot express the logic in a single statement, you would in Ruby simply pass a Proc or a block instead, so that the problem of the ugly syntax for referencing methods doesn't even arise.

You can wrap a method in a Method object (which essentially duck-types Proc) by calling the Object#method method on an object (which will give you a Method whose self is bound to that particular object):

foo_bound = method(:foo)

foo_bound.('Hello')
# Hello

You can also use one of the methods in the Module#instance_method family to get an UnboundMethod from a module (or class, obviously, since a class is-a module), which you can then UnboundMethod#bind to a particular object and call. (I think Python has the same concepts, albeit with a different implementation: an unbound method simply takes the self argument explicitly, just like the way it is declared.)

foo_unbound = Object.instance_method(:foo) # this is an UnboundMethod

foo_unbound.('Hello')
# NoMethodError: undefined method `call' for #<UnboundMethod: Object#foo>

foo_rebound = foo_unbound.bind(self)       # this is a Method

foo_rebound.('Hello')
# Hello

Note that you can only bind an UnboundMethod to an object which is an instance of the module you took the method from. You cannot use UnboundMethods to "transplant" behavior between unrelated modules:

bar = module Foo; def bar; puts 'Bye' end; self end.instance_method(:bar)
module Foo; def bar; puts 'Hello' end end

obj = Object.new
bar.bind(obj)
# TypeError: bind argument must be an instance of Foo

obj.extend(Foo)
bar.bind(obj).()
# Bye
obj.bar
# Hello

Note, however, that both the Method and the UnboundMethod are wrappers around the method, not the method itself. Methods are not objects in Ruby. (Contrary to what I have written in other answers, BTW. I really need to go back and fix those.) You can wrap them in objects, but they aren't objects, and you can see that because you essentially get all the same problems you always get with wrappers: identity and state. If you call method multiple times for the same method, you will get a different Method object every time. If you try to store some state on that Method object (such as Python-style __doc__strings, for example), that state will be private to that particular instance, and if you try to retrieve your docstring again via method, you will find that it is gone.

There is also syntactic sugar in the form of the method reference operator .::

bound_method = obj.:foo

Which is identical to

bound_method = obj.method(:foo)
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • 1
    Good answer, as usual :-) One point I don't quite agree with is identity with methods, which is handled better than you seem to imply. Yes, you get different objects, but they are `==` to one another, even funky methods like the ones obtained through `respond_to_missing?`. – Marc-André Lafortune Nov 28 '10 at 10:44
  • @guettli: I'd say it's a trade-off. In Python, you can simply reference a method by leaving off the parentheses, but OTOH you cannot call them without. In Ruby, you can call them without parentheses, so you need to a different way to reference them, and what better way to get a reference to a method in an object-oriented language than to call a method asking for a reference? – Jörg W Mittag Mar 12 '14 at 13:35
  • 1
    The important part about methods in ruby being callable without parentheses is that it helps enforce the Uniform Access Principle: that is, all member access is via methods in ruby; in Python, directly getting a integer member (say) would be obj.member, while calling a method that returns an integer is obj.member(); in ruby, it is always a method. This means that you can change from a 'simple' accessor (such as that provided by `attr_accessor` and a more complex implementation, without callers having to change their usage. – philomory Nov 05 '16 at 21:36
  • If this answers the OP's question then it's unclear how. Is that the `obj.:foo` example at the very end? – siimphh Jul 04 '20 at 10:56
10

You can use the method instance method inherited from Object to retrieve a Method object, which essentially is a Proc object which you can invoke call on.

In the console, you'd do this:

fooMethod = self.method(:foo) #fooMethod is a Method object

fooMethod.call #invokes fooMethod

alt text

Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • The "self" is not needed. x = method(:foo); x.call works fine. – steenslag Nov 27 '10 at 23:52
  • 2
    @steenslag It's okay to be a bit verbose sometimes you know. You are right by the way :) – Jacob Relkin Nov 27 '10 at 23:54
  • I use `self` when I am trying to make it more clear what is going on. Sometimes it's obvious where a method is coming from, and sometimes adding `self` helps point the way visually. It's a self-documenting thing, no pun intended. – the Tin Man Nov 28 '10 at 00:13
  • Wait a second... so what exactly is self in this example? – Jason Baker Nov 28 '10 at 00:23
  • @Jacob - Forgive me if I'm being dense, but I'm new to Ruby. What exactly is main? My first reaction is to treat it as some kind of namespace, but based on the fact that we're referring to self it sounds like an actual class. – Jason Baker Nov 28 '10 at 00:30
  • 1
    @Jason `main` is the main execution context of every ruby application, it is a wrapper class of the entire lifetime of the app if you will. – Jacob Relkin Nov 28 '10 at 00:32
  • `main` is *not* a class, it is an *object*. In particular, it is the object which is `self` when no other object is around, i.e. at the top-level. – Jörg W Mittag Nov 28 '10 at 00:37
  • 3
    I just thought of a better way to explain it, by contrasting it with the other occurences of `self`: within a method, `self` will be dynamically bound to the receiver, whenever the method is called. Within a module definition body, `self` is the module itself. (That's why `def self.foo` works for defining "class" methods.) Within a script body (which basically means within a file but outside of any other kind of body), `self` is `main`. (I think this also applies to a string passed from the commandline via `-e`.) – Jörg W Mittag Nov 28 '10 at 00:46
  • 1
    Special case: in a block, `self` is lexically scoped, i.e. `self` inside the block is whatever it is *outside* of the block, but when a block is passed to `instance_exec` or `instance_eval`, then `self` in the block is actually the receiver of the `instance_exec` or `instance_eval` (which is one of the reasons these two methods should be avoided). – Jörg W Mittag Nov 28 '10 at 00:47
  • camelCase in Ruby? Heresy! :p – Phrogz Nov 28 '10 at 05:32
1

The (main) difference between functions and methods as copied from https://stackoverflow.com/a/26620095/226255

Functions are defined outside of classes, while methods are defined inside of and part of classes.

Ruby does not have functions and your def foo ends up being a method for the Object class.

If you insist on defining foo like you're doing above, you can extract its "functionality" by doing this:

def foo(a,b)
 a+b
end

x = method(:foo).to_proc
x.call(1,2)
=> 3

Explanation:

> method(:foo) # this is Object.method(:foo), returns a Method object bound to 
# object of type 'Class(Object)'
=> #<Method: Class(Object)#foo>

method(:foo).to_proc
# a Proc that can be called without the original object the method was bound to
=> #<Proc:0x007f97845f35e8 (lambda)>

Important note:

to_proc "copies" the method's object's associated instance variables if any. Consider this:

class Person
  def initialize(name)
    @name = name
  end

  def greet
    puts "hello #{@name}"
  end
end

greet = Person.new('Abdo').method(:greet) 
# note that Person.method(:greet) returns an UnboundMethod and cannot be called 
# unless you bind it to an object

> greet.call
hello Abdo
=> nil

Conceptually, if you want a "function" that would work on a certain type of objects, it should be a method and you should organize your code as such. If you only need your "function" in a certain context and wish to pass it around, use lambdas:

greet = lambda { |person| "hello #{person}" }
yell_at = lambda { |person| "HELLO #{person.upcase}" }

def do_to_person(person, m)
  m.call(person)
end

do_to_person('Abdo', greet)
Community
  • 1
  • 1
Abdo
  • 13,549
  • 10
  • 79
  • 98
1

Ruby supports proc and lambda which in other languages might be called anonymous functions or closures, depending on how they are used. They might be closer to what you are looking for.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303