How do I reference a function in Ruby?
Ruby doesn't have functions. It only has methods (which aren't first-class) and Proc
s 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 Proc
s 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 Proc
s and Method
s 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 Proc
s 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)
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
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.